Elad Benda2
Elad Benda2

Reputation: 15492

Is there a difference between `listView.invalidate()` and `adapter.notifyDataHasChanged()`?

I have a list of items.

I want to delete an item in a long push.

I saw this post and it worked for me.

just out of curiosity i wonder why other solution didn't work for me:

sol 1

I register the list to context menu:

registerForContextMenu(listView);

and then:

@Override
public void onCreateContextMenu(ContextMenu menu, View v,
                                ContextMenu.ContextMenuInfo menuInfo) {
    if (v.getId()==R.id.comments_list) {
        MenuInflater inflater = getActivity().getMenuInflater();
        inflater.inflate(R.menu.phone_list_contextual_menu, menu);
    }
}

@Override
public boolean onContextItemSelected(MenuItem item) {
    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
    switch(item.getItemId()) {
        case R.id.edit: {
           return true;
        }
        case R.id.delete: {
            comments.remove(info.id);
            listView.invalidate();
            return true;
        }
        default: {
            return super.onContextItemSelected(item);
        }
    }
}

Is there a difference between

listView.invalidate() and adapter.notifyDataHasChanged() ? beside the subject of the call?

what am I missing in order for the remove to work?

sol 2

listView.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        int position = (int) v.getTag();
        comments.remove(position);
        listView.invalidate();
        return true;
    }
});

instead of

  listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener(){
        @Override
        public boolean onItemLongClick(AdapterView<?> av, View v, int pos, long id) {
            comments.remove(pos);
            //listView.invalidate();
            arrayAdapter.notifyDataSetChanged();
            return true;
        }
    });

I understand setOnItemLongClickListener is more suitable for my need than setOnLongClickListener but yet

why didn't this worked for me?

Upvotes: 3

Views: 1126

Answers (2)

marcinj
marcinj

Reputation: 50026

Is there a difference between

listView.invalidate() and adapter.notifyDataHasChanged() ? beside the subject of the call?

To my understanding adapter.notifyDataHasChanged() will do what listView.invalidate() plus more. That means it will also include change in number of items, and possibly inform other observers of data change. Relevant code is here:

http://androidxref.com/5.0.0_r2/xref/frameworks/base/core/java/android/widget/AdapterView.java#798

this is for notifyDataHasChanged(), as you can see mItemCount is udpated with new value. This means if you add more items to your arrayadapter, then invalidate, or better invalidateViews will not show them, at least at the end of list. One thing I have noticed is that above code has no invalidate call - maybe its called by some other methods.

Below is source code for invalidateViews (which is I think more proper than Invalidate):

http://androidxref.com/5.0.0_r2/xref/frameworks/base/core/java/android/widget/AbsListView.java#5078

It has no code to update count of item.

If you search source code for android sources, you will find only few cases when invalidateViews is called, some of those places are optimization hacks.

Upvotes: 1

pat
pat

Reputation: 1015

The difference is that invalidate causes all your views in the list to be scrapped and redrawn. Note I said views so that is what you are actually seeing on the screen (for example you can have 3 views on screen but 20 items in your list)

notifyDataHasChanged on the other hand tells the adapter that the contents have changed and the adapter needs to re-run its methods on the content to refresh the list.

You almost always want to use notifyDataHasChanged but it depends on exactly what you are trying to accomplish.

Hope that helps.

Upvotes: 1

Related Questions