ListView异常:The content of the adapter has changed but ListView did not receive a notification


此异常的主要原因是:Adapter的数据改变了,但没有及时的通知notifyDataSetChanged()。

为了避免此问题,将Activity中的原始数据和Adapter中的数据进行分离,当业务数据在Activity中变化变化时,不影响到Adapter。

public class SdcardListAdapter extends BaseAdapter {

	private Context context;
	private List<SdcardSimpleInfo> dataList = new ArrayList<SdcardSimpleInfo>();

	public SdcardListAdapter(Context context, List<SdcardSimpleInfo> data) {
		this.context = context;
		this.dataList.addAll(data);
	}
	
	public void setData(List<SdcardSimpleInfo> data){
		this.dataList.clear();
		this.dataList.addAll(data);
	}

当需要将改变数据在ListView中体现时,调用Adapter中的setData(...)函数,再通知更新notifyDataSetChanged()。


后来发现:其实如上的操作并没有完全分离两边的数据。当在Adapter中改变数据dataList中的item值时,Acvitity中对应的数据也会发生变化。

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

	if (view == null) {
		LayoutInflater inflater = LayoutInflater.from(context);
		view = inflater.inflate(R.layout.sdcard_list_item, null);

		holder = new ViewHolder();
		holder.titleView = (TextView) view.findViewById(R.id.sdcard_title);
		holder.choseView = (CheckBox) view.findViewById(R.id.sdcard_chose);
		view.setTag(holder);
	} else {
		holder = (ViewHolder) view.getTag();
	}

	final SdcardSimpleInfo info = dataList.get(position);
	holder.titleView.setText(info.getTitle());
	holder.choseView.setChecked(info.isChose());
	holder.choseView.setOnClickListener(new OnClickListener() {
			
		@Override
		public void onClick(View v) {
			info.setChose(!info.isChose());
				
		}
	});


	return view;
}


之前错误的认为ArrayList.addAll(...)是深拷贝,其实是浅拷贝,只拷贝了源List中的Item地址,源List和目标List中的元素指向相同的Item地址,因此操作其中一个会体现到另一个。在此处也是一个好处,因为在Adapter中的操作结果,可以在Activity中直接得到,不用再从Adapter中函数获取。


ArrayList.addAll(...)的实现代码如下:

public boolean addAll(Collection<? extends E> collection) {
        Object[] newPart = collection.toArray();
        int newPartSize = newPart.length;
        if (newPartSize == 0) {
            return false;
        }
        Object[] a = array;
        int s = size;
        int newSize = s + newPartSize; // If add overflows, arraycopy will fail
        if (newSize > a.length) {
            int newCapacity = newCapacity(newSize - 1);  // ~33% growth room
            Object[] newArray = new Object[newCapacity];
            System.arraycopy(a, 0, newArray, 0, s);
            array = a = newArray;
        }
        System.arraycopy(newPart, 0, a, s, newPartSize);
        size = newSize;
        modCount++;
        return true;
}

因此其主要是调用了System.arraycopy(...)来实现浅拷贝。这个函数,对于基本数据类型的数组,是数值传递;对于对象类型,是引用传递,复制的是对象数据的地址。



参考:http://blog.sina.com.cn/s/blog_3e333c4a01011kpd.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值