Question

I get this error with my ListView:

java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes.

In my app I have a ListView with a CustomAdapter.

In the OnCreate Method I have:

list = new ArrayList<FriendVO>();
mListView = (ListView) this.findViewById(R.id.listView1);
    mFriendAdapter =  new FriendAdapter(null);
    mListView.setAdapter(mFriendAdapter);

Also I have an AsyncHttpResponseHandler that gets data from my webservice to fill my ListView. Everthing works fine with that. In the method onFinish() of the AsyncHttpResponseHandler I am updating the data of my List View.

When I get to the method onFinish() I have already the list with the data.

@Override
        public void onFinish(){

                    mFriendAdapter.setData(list);
                    mListView.setOnItemClickListener(itemClickListener);
        }

Here is my Custom Adapter:

private class FriendAdapter extends BaseAdapter {

    private List<FriendVO> mData;
    private LayoutInflater mInflater;

    public FriendAdapter(List<FriendVO> data) {
        mData = data;
        mInflater = FaceVsFaceActivity.this.getLayoutInflater();
    }

    public void setData(List<FriendVO> data) {
        mData = data;
        this.notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        if (mData != null)
            return mData.size();
        else
            return 0;
    }

    @Override
    public Object getItem(int position) {
        return mData.get(position);
    }

    @Override
    public long getItemId(int position) {
        // TODO: If id is needed, change it
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        RowViewsHolder holder;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.friend_row, parent, false);
            holder = new RowViewsHolder(convertView);
            convertView.setTag(holder); // Save inside view the holder.
        } else {
            holder = (RowViewsHolder) convertView.getTag();
        }

        FriendVO vo = mData.get(position);
        holder.eventName.setText(vo.getName());

        holder.eventImage.setImageResource(R.drawable.image);

        return convertView; 
    }   
}

private class RowViewsHolder {
    private ImageView eventImage;
    private TextView eventName;

    public RowViewsHolder(View rowView) {
        eventImage = (ImageView) rowView.findViewById(R.id.img_friend);
        eventName = (TextView) rowView.findViewById(R.id.friend_name);

        }
}

What solution could be for this? I think I get the error when I use the list (Scroll, click) and the data is beeing updated. Please some little help.

Was it helpful?

Solution

from the AsyncHttpResponseHandler documentation "All your processing should be handled in one of those 4 methods and then either call to run on UI thread a new runnable, or handle in onFinish which runs on the UI thread"

So setting the adapter in onFinish isn't the issue.

I'm not a fan of setting things to null then changing them later if you don't need to, so I made a change to your onCreate. Also, I suggest calling notifyDataSetChanged rather than setData. Give this a shot and let me know what happens.

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_contact_picker_main);

        list = new ArrayList<FriendVO>();
        mListView = (ListView) this.findViewById(R.id.listView1);

        mFriendAdapter =  new FriendAdapter(list);
        mListView.setAdapter(mFriendAdapter);

    }

@Override
    public void onFinish(){

        mFriendAdapter.notifyDataSetChanged();
        mListView.setOnItemClickListener(itemClickListener);
    }

Also, change this:

@Override
    public int getCount() {
        if (mData != null)
            return mData.size();
        else
            return 0;
    }

to this:

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

You're mData should never be null (at worst, it'll be empty so size will be zero) and if it is, there's a problem you need to fix. This null check can only cause a problem to go unnoticed which you don't want.

And finally. Your adapter is set to allow any object to be passed as mData. Change your getItem from Object to FriendVO to give you better control and consistency.

OTHER TIPS

You are modifying your adapter from a thread that is not the UI thread, and Android doesn't like that. You can use the Activity.runOnUiThread() method to call your mFriendAdapter.setData(list); call and avoid this exception. You'll need to wrap it in a Runnable.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top