`listView.invalidate()` 和 `adapter.notifyDataHasChanged()` 之间有区别吗?

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

我有一个物品清单。

我想长按删除一个项目。

我看到了这个 post,它对我有用。

出于好奇,我想知道为什么其他解决方案对我不起作用:

溶胶 1

我将列表注册到上下文菜单:

registerForContextMenu(listView);

然后:

@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);
        }
    }
}

有区别吗

listView.invalidate()adapter.notifyDataHasChanged() ?在通话主题旁边?

我缺少什么才能使删除工作正常进行?

溶胶 2

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

而不是

  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;
        }
    });

我知道 setOnItemLongClickListenersetOnLongClickListener 更适合我的需要,但是

为什么这对我不起作用?

不同之处在于 invalidate 会导致您在列表中的所有视图都被废弃并重新绘制。请注意,我说的是视图,所以这就是您在屏幕上实际看到的内容(例如,您可以在屏幕上有 3 个视图,但列表中有 20 个项目)

另一方面,

notifyDataHasChanged 告诉适配器内容已更改,适配器需要重新运行 其对内容的方法以刷新列表。

您几乎总是想使用 notifyDataHasChanged 但这取决于您要完成的具体目标。

希望对您有所帮助。

Is there a difference between

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

据我了解,adapter.notifyDataHasChanged() 会做 listView.invalidate() 的事情,而且还会做更多。这意味着它还将包括项目数量的变化,并可能将数据变化通知其他观察者。相关代码在这里:

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

这是针对 notifyDataHasChanged() 的,如您所见,mItemCount 已更新为新值。这意味着如果您向 arrayadapter 添加更多项,则 invalidate 或更好的 invalidateViews 将不会显示它们,至少在列表末尾是这样。我注意到的一件事是上面的代码没有无效调用 - 可能是由其他一些方法调用的。

下面是 invalidateViews 的源代码(我认为这比 Invalidate 更合适):

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

它没有更新项目数量的代码。

如果您搜索 android 来源的源代码,您会发现调用 invalidateViews 的情况很少,其中一些地方是优化黑客。