Adapter.notifyDataSetChanged()数据改变却不刷新的原因

今天做Android作业的时候发现个现象:

List mSongVOs = getSongs(A);//数据A
SongAdapter mSongAdapter = new SongAdapter(getApplicationContext(), mSongVOs);//用数据初始化适配器
lvMusicList.setAdapter(mSongAdapter);//为ListView绑定适配器

//情况1.可以刷新Listview数据
mSongVOs.remove(x);
mSongAdapter.notifyDataSetChanged();

//情况2.不刷新
mSongVOs=getSongs(B);//数据B
mSongAdapter.notifyDataSetChanged();

//情况3.可以刷新
mSongVOs.clear();
mSongVOs.addAll(helper.getAudios());
mSongAdapter.notifyDataSetChanged();

摸索了一下,找到了原因:
查看SongAdapter的构造函数:

public class SongAdapter extends BaseAdapter {

    private List mData;
    private Context mContext;

    public SongAdapter(Context context, List songs) {
        mContext = context;
        mData = songs;
    }

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

Adapter通常的写法都是用一个成员变量mData持有着对数据的引用,之后ListView的刷新都是通过Adapter.getItem()等方法进行更新,而这些方法访问的数据时这个mData指向的数据。如果这个数据不变,那么notifyDataSetChanged自然不会刷新。

在情况1、3中,局部变量mSongVOs和SongAdapter的成员变量mData指向的是同一块内存地址,即数据A,因此mSongVOs修改A后,notifyDataSetChanged通过mData再访问A时发现数据变了,所以就更新了ListView。
在情况2中,局部变量mSongVOs通过getSong(B)获取新数据B,实际是mSongVOs指向了内存中另外一块地址B,而此时mData指向的仍然是A。因此notifyDataSetChanged观察到A始终没有变化,因此不刷新。

所以,情况2,并不是Adapter“数据变了却不刷新”,而是“数据根本没变”。
而网上说重新对adapter绑定即可刷新,实际上就是重新绑定了成员变量mData,因此可以刷新。

情况2、3的业务逻辑是换了一整批数据,编程上情况2似乎是很直观和合理的,但是得注意了,得用第三种写法。

再次论内存分析的重要性!

你可能感兴趣的:(android)