0

I have a custom ListView that I fill with my custom ArrayAdapter. I read and parse json data from URLs and fill the ListView with this. It works perfectly when I read the first file. Now I want to be able to add more data (older posts) to my ListView, though. I've added a "Load More" button as a footer to the ListView, when I've loaded the new data though and try to scroll through it I get this error:

java.lang.IndexOutOfBoundsException: Invalid index 25, size is 25

At first I didn't understand at all why this was, now I realize it's that my ListView isn't expandable. When I search google for expandable ListViews the custom adapters extend BaseExpandableListAdapter, but I'm not sure how to implement that in my application.. My custom arrayadapter is defined like this:

private class StreamAdapter extends ArrayAdapter<Message>

Message being one of my classes.

This is how I display the data:

private void DisplayData() {
    // If the request was successfull then notify the adapter to display the data
    if(success) {

        if(dataAdapter.isEmpty())
        {
            dataAdapter.addAll(dataList);
            dataAdapter.notifyDataSetChanged();
        }
        // If the listview isn't empty we want to erase what's there and then add the older posts to display
        else
        {
            /** Add currently displayed messages to a temporary arraylist, clear the listview, then add both arraylists in the correct order **/
            int size = messageList.getTop();
            ArrayList<Message> temp = new ArrayList<Message>();

            for(int i = 0; i < size; i++)
            {
                temp.add(dataAdapter.getItem(i));
            }
            dataAdapter.clear();
            temp.addAll(dataList);

            dataAdapter.addAll(temp);
            dataAdapter.notifyDataSetChanged();
        }
    }
}

The whole temp-ArrayList-thing was the only way I could come up with to get the newly loaded data (but oldest posts) at the bottom of the listview instead of at the top.

Is there any way to easily make my ListView expandable or do I have to rewrite my entire StreamAdapter class?

Kristina

EDIT: Here's the code for my StreamAdapter class, I left parts out though as I'm fairly sure it's not relevant and just adds to a bunch of code.

private class StreamAdapter extends ArrayAdapter {

public StreamAdapter(Context context, int textViewResourceId, ArrayList<Message> dataList) 
{
    super(context,textViewResourceId, dataList);
}

private class ViewHolder {
    ImageView thumbnail;
    TextView display_name;
    TextView username;
    TextView created_at;
    TextView text;
    ImageView comments;
    TextView nr_comments;
    @SuppressWarnings("unused")
    ImageView like;
    TextView nr_likes;
    @SuppressWarnings("unused")
    ImageView starred;
    TextView nr_starred;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = null;

    if(convertView == null)
    {
        LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = vi.inflate(R.layout.data_row, null);


        holder = new ViewHolder();
        holder.thumbnail = (ImageView) convertView.findViewById(R.id.thumbnail);
        holder.display_name = (TextView) convertView.findViewById(R.id.display_name);               
        holder.username = (TextView) convertView.findViewById(R.id.username);
        holder.created_at = (TextView) convertView.findViewById(R.id.created_at);
        holder.text = (TextView) convertView.findViewById(R.id.text);
        holder.comments = (ImageView) convertView.findViewById(R.id.comments);
        holder.nr_comments = (TextView) convertView.findViewById(R.id.nr_comments);
        holder.like = (ImageView) convertView.findViewById(R.id.like);
        holder.nr_likes = (TextView) convertView.findViewById(R.id.nr_likes);
        holder.starred = (ImageView) convertView.findViewById(R.id.starred);
        holder.nr_starred = (TextView) convertView.findViewById(R.id.nr_starred);

        convertView.setTag(holder);
    }
    else
    {
        holder = (ViewHolder) convertView.getTag();
    }

    final Message data = dataList.get(position);
    holder.thumbnail.setImageDrawable(getResources().getDrawable(R.drawable.owl_thumbnail));
    holder.display_name.setText(data.created_by.getDisplay_name());
    holder.username.setText("@"+data.created_by.getUsername());
    holder.created_at.setText(data.getCreated_at());
    holder.nr_comments.setText(Integer.toString(data.getComments().length));
    holder.nr_likes.setText(Integer.toString(data.getLiked_by().length));
    holder.nr_starred.setText(Integer.toString(data.getStarred_by().length));


    // Code to make certain text in the text-textview clickable

    // Clickhandler for the username (display_name)
    holder.display_name.setOnClickListener(new OnClickListener() {
        // Code
    });

    // Clickhandler for comments
    holder.comments.setOnClickListener(new OnClickListener() {
        //Code
    });

    return convertView;
}

}

Phoebe
  • 169
  • 3
  • 10

3 Answers3

0

No, you shouldn't use ExpandableListAdapter, and you don't have to provide a new implementation of the adapter. The exception you're getting is probably due to a bad handling of an array, as you would have already guessed. I had a similar problem, but i was using adapters with Cursor (querying a database) so I think that notifydataSetChanged() should be enough for the adapter to reload data and display them after the adapter was filled with the additional data.

ExpandableListAdapter is used when you have to display data in the PARENT -> CHILDREN way, so with ExpandableListView you see a list of parent items, each one with multiple child items, each parent expands/collapses (and thus shows/hides children) when you click on it.

fiipi
  • 663
  • 6
  • 20
0

Instead of adding new data to adapter items try getting a reference to your data list from adapter and add this data into it for ex:

private class StreamAdapter extends ArrayAdapter {

private  ArrayList<Message> dataList;
public StreamAdapter(Context context, int textViewResourceId, ArrayList<Message> dataList) 
{
    super(context,textViewResourceId, dataList);
    this.dataList=dataList;
}

public  ArrayList<Message> getDataList(){
   return dataList;
}

public void setDataList(ArrayList<Message> dataList){
   this.dataList=dataList;
}

...
...

}

And in when you update it

private void DisplayData() {
    // If the request was successfull then notify the adapter to display the data
    if(success) {

            ArrayList<Message> temp = dataAdapter.getDataList();

            for(int i = 0; i < dataList.size(); i++)
            {
                temp.add(i,dataList.get(i));
            }

            dataAdapter.notifyDataSetChanged();
        }
}

This should work, try it and let me know.

Also override following function inside adapter

@Override
    public int getCount() {
        return dataList.size();
    }

EDIT

private void DisplayData() {
    // If the request was successfull then notify the adapter to display the data
    if(success) {

            ArrayList<Message> temp = dataAdapter.getDataList();
            dataList.addAll(temp);
            dataAdapter.setDataList(dataList);

            dataAdapter.notifyDataSetChanged();
        }
}

EDIT 2

private void DisplayData() {
    // If the request was successfull then notify the adapter to display the data
    if(success) {

            ArrayList<Message> temp = dataAdapter.getDataList();
            temp.addAll(dataList);
            dataAdapter.notifyDataSetChanged();
        }
}
vipul mittal
  • 17,343
  • 3
  • 41
  • 44
  • just don't let your datalist to be null set an empty list instead – vipul mittal Dec 05 '13 at 11:21
  • It gave me the same error but with 50 instead of 25 "java.lang.IndexOutOfBoundsException: Invalid index 50, size is 50". And I declared my dataList "private ArrayList dataList = new ArrayList();" – Phoebe Dec 05 '13 at 12:01
  • what is the size of your list? – vipul mittal Dec 05 '13 at 12:07
  • I added the getCountfunction now, and that solves the crashing problem, however now the data I'm loading to the listview that are the old posts are on top, and I need it to be reversed. I have to run off to catch a train now but will look and try more on Monday, thanks for your help so far! :) – Phoebe Dec 05 '13 at 12:19
  • Well as I said on Thursday it doesn't crash now, but I'm still fighting with the ArrayLists when it comes to getting the messages added in the correct order. I'm trying this code when displaying data now, if the dataAdapter isn't empty (looks bad when pasting..) Oh well: ArrayList currentFeed = dataAdapter.getDataList(); ArrayList temp = new ArrayList(); dataAdapter.clear(); for(int i = 0; i < dataList.size(); i++) { temp.add(i, dataList.get(i)); } for(int i = 0; i < temp.size(); i++) { currentFeed.add(temp.get(i)); } – Phoebe Dec 10 '13 at 09:06
  • If that does not work i have edited my ans try that. – vipul mittal Dec 10 '13 at 09:35
  • Still gets the loaded messages on top of the listview.. :) – Phoebe Dec 10 '13 at 10:13
  • you want to show new messages on top of the old messages ryt?? – vipul mittal Dec 10 '13 at 10:15
  • Well, yes and no depending on what you mean with new. Think of it as a twitter feed, I want the messages I'm loading (which are the older ones) to be in the bottom of the listview – Phoebe Dec 10 '13 at 10:22
  • try my edited ans. I think what you need is to add all the new items to the bottom of the list that you already have. And by new items i mean the ones you just laoded(old messages). – vipul mittal Dec 10 '13 at 10:26
  • That seems to have done the trick! Wow, thank you so much for letting me bug you about it (also simultaneously tried to debug it with a friend and just started to realize "why don't I just add them to the dataList..?") Thank you! – Phoebe Dec 10 '13 at 10:32
  • exactly i was going to suggest that but thought to let you first check this is what you want – vipul mittal Dec 10 '13 at 10:33
0

Try to replace

int size = messageList.getTop();

with

int size = dataAdapter.getCount();
Mohamed_AbdAllah
  • 5,311
  • 3
  • 28
  • 47