关于 android listview 加载数据错位(错乱)问题
来源:互联网 发布:windows优化大师64 编辑:程序博客网 时间:2024/05/19 18:45
一般的关于Adapter中getView的写法不外乎以下形式:
public
ViewgetView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
if (convertView == null)
{
convertView = mLayout.inflate(R.layout....);
holder =new ViewHolder();
holder.textView = (TextView) convertView.findViewById(R.id.textview);
... ...
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
holder.textView.setText(mText + position);
return convertView;
}
在Android源码中关于getView方法的实现就是采用的以上形式,如ArrayAdapter等。因为这种写法的好处也是显而易见的,如果该position的convertview曾经被加载过,在数据集合未被改动的前提下,系统会自动将该position的convertview缓存起来,避免重复加载耗费资源。
我自己的代码:
@Overridepublic View getView(int position, View view, ViewGroup parent) { final ViewHolder mViewHolder; if(null == view){ mViewHolder = new ViewHolder(); view = LayoutInflater.from(mContext).inflate(R.layout.fragment_new_order_list_item, null); mViewHolder.txtPaystatus = (TextView) view.findViewById(R.id.order_pay_status); mViewHolder.txtOrdertime = (TextView) view.findViewById(R.id.order_time); mViewHolder.txtCustomerName = (TextView) view.findViewById(R.id.customer_name); mViewHolder.txtCustomerAddress = (TextView) view.findViewById(R.id.customer_address); mViewHolder.txtOrderSendTime = (TextView) view.findViewById(R.id.customer_post_time); mViewHolder.txtOrderGoodsDes = (TextView) view.findViewById(R.id.customer_list_goods_des); mViewHolder.txtCustomerPhone = (TextView) view.findViewById(R.id.customer_phone); mViewHolder.btnOrderOk = (Button) view.findViewById(R.id.order_ok); mViewHolder.btnOrderCancel = (Button) view.findViewById(R.id.order_cancel); mViewHolder.listgoods = (ListView) view.findViewById(R.id.customer_list_goods); if(listOrder.get(position).getPaystatus() == 0) { mViewHolder.txtPaystatus.setText("未付款"); } else { mViewHolder.txtPaystatus.setText("已付款"); } mViewHolder.txtOrdertime.setText(listOrder.get(position).getOrdertime()); mViewHolder.txtCustomerName.setText(listOrder.get(position).getAcceptname()); mViewHolder.txtCustomerAddress.setText(listOrder.get(position).getAcceptlocation()); mViewHolder.txtOrderSendTime.setText(listOrder.get(position).getGoodsarrivetime()); mViewHolder.txtOrderGoodsDes.setText(listOrder.get(position).getOrderSeller().getRemark()); mViewHolder.txtCustomerPhone.setText(listOrder.get(position).getAcceptphonenum()); OrderGoodsListItemAdapter mOrderGoodsListItemAdapter = new OrderGoodsListItemAdapter(mContext, listOrder.get(position).getOrderSeller().getLstOrderGoods()); mViewHolder.listgoods.setAdapter(mOrderGoodsListItemAdapter); setListViewHeightOnChildren(mViewHolder.listgoods); final int index = position; mViewHolder.btnOrderOk.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v) { String sellerorderid = String.valueOf(listOrder.get(index).getOrderSeller().getSellerorderid()); String token = App.getInstance().sellerInfo.getToken(); orderService.modifyOrder(sellerorderid, "1", token) .subscribe(new Action1<String>() { @Override public void call(String s) { Toast.makeText(mContext, s, Toast.LENGTH_SHORT).show(); newOrderFragment.listOrder.clear(); newOrderFragment.pageindex = 1; newOrderFragment.requestData(); App.isNeedFreshData = true; App.isNeedFresShophData = true; } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { Toast.makeText(mContext, throwable.getMessage(), Toast.LENGTH_SHORT).show(); } }); } }); mViewHolder.btnOrderCancel.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v) { String sellerorderid = String.valueOf(listOrder.get(index).getOrderSeller().getSellerorderid()); String token = App.getInstance().sellerInfo.getToken(); orderService.modifyOrder(sellerorderid, "2", token) .subscribe(new Action1<String>() { @Override public void call(String s) { Toast.makeText(mContext, s, Toast.LENGTH_SHORT).show(); newOrderFragment.listOrder.clear(); newOrderFragment.pageindex = 1; newOrderFragment.requestData(); App.isNeedFreshData = true; App.isNeedFresShophData = true; } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { Toast.makeText(mContext, throwable.getMessage(), Toast.LENGTH_SHORT).show(); } }); } }); view.setTag(mViewHolder); } else { mViewHolder = (ViewHolder) view.getTag(); } return view;}
然后问题就来了,当时我就”自作小聪明“或者说“没有注意”,觉得当convertview==null时只是做了item布局的加载以及相关控件ID的绑定操作,为什么连内容的加载操作也放入其中呢,这样下次加载缓存是就省去内容set的操作了,然后就出现了滑动ListView后数据显示错位的问题。
剖析原因:
后来看源码发现,原来AbListView中获取getView()和滑动操作是异步进行的,其中滑动操作在一个FlingRunnable的支线程中运行,所以这就导致了在ListView在滑动时可能已经滑动到了第十行,但可能第二行的数据这时就被直接使用了,这就是导致数据加载错乱的根本原因。
附上源码中对FlingRunnable的注释:
/** * Responsible for fling behavior. Use {@link #start(int)} to * initiate a fling. Each frame of the fling is handled in {@link #run()}. * A FlingRunnable will keep re-posting itself until the fling is done. * */private class FlingRunnable implements Runnable { /** * Tracks the decay of a fling scroll */ private final OverScroller mScroller; ... ...}
解决方法
所以唯一的解决方法就是只在convertview中缓存该ChildView的layout,但ChildView 中的数据必须每次都重新获取并加载。
修改后的代码:
@Overridepublic View getView(int position, View view, ViewGroup parent) { final ViewHolder mViewHolder; if(null == view){ mViewHolder = new ViewHolder(); view = LayoutInflater.from(mContext).inflate(R.layout.fragment_new_order_list_item, null); mViewHolder.txtPaystatus = (TextView) view.findViewById(R.id.order_pay_status); mViewHolder.txtOrdertime = (TextView) view.findViewById(R.id.order_time); mViewHolder.txtCustomerName = (TextView) view.findViewById(R.id.customer_name); mViewHolder.txtCustomerAddress = (TextView) view.findViewById(R.id.customer_address); mViewHolder.txtOrderSendTime = (TextView) view.findViewById(R.id.customer_post_time); mViewHolder.txtOrderGoodsDes = (TextView) view.findViewById(R.id.customer_list_goods_des); mViewHolder.txtCustomerPhone = (TextView) view.findViewById(R.id.customer_phone); mViewHolder.btnOrderOk = (Button) view.findViewById(R.id.order_ok); mViewHolder.btnOrderCancel = (Button) view.findViewById(R.id.order_cancel); mViewHolder.listgoods = (ListView) view.findViewById(R.id.customer_list_goods); view.setTag(mViewHolder); } else { mViewHolder = (ViewHolder) view.getTag(); } if(listOrder.get(position).getPaystatus() == 0) { mViewHolder.txtPaystatus.setText("未付款"); } else { mViewHolder.txtPaystatus.setText("已付款"); } mViewHolder.txtOrdertime.setText(listOrder.get(position).getOrdertime()); mViewHolder.txtCustomerName.setText(listOrder.get(position).getAcceptname()); mViewHolder.txtCustomerAddress.setText(listOrder.get(position).getAcceptlocation()); mViewHolder.txtOrderSendTime.setText(listOrder.get(position).getGoodsarrivetime()); mViewHolder.txtOrderGoodsDes.setText(listOrder.get(position).getOrderSeller().getRemark()); mViewHolder.txtCustomerPhone.setText(listOrder.get(position).getAcceptphonenum()); OrderGoodsListItemAdapter mOrderGoodsListItemAdapter = new OrderGoodsListItemAdapter(mContext, listOrder.get(position).getOrderSeller().getLstOrderGoods()); mViewHolder.listgoods.setAdapter(mOrderGoodsListItemAdapter); setListViewHeightOnChildren(mViewHolder.listgoods); final int index = position; mViewHolder.btnOrderOk.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v) { String sellerorderid = String.valueOf(listOrder.get(index).getOrderSeller().getSellerorderid()); String token = App.getInstance().sellerInfo.getToken(); orderService.modifyOrder(sellerorderid, "1", token) .subscribe(new Action1<String>() { @Override public void call(String s) { Toast.makeText(mContext, s, Toast.LENGTH_SHORT).show(); newOrderFragment.listOrder.clear(); newOrderFragment.pageindex = 1; newOrderFragment.requestData(); App.isNeedFreshData = true; App.isNeedFresShophData = true; } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { Toast.makeText(mContext, throwable.getMessage(), Toast.LENGTH_SHORT).show(); } }); } }); mViewHolder.btnOrderCancel.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v) { String sellerorderid = String.valueOf(listOrder.get(index).getOrderSeller().getSellerorderid()); String token = App.getInstance().sellerInfo.getToken(); orderService.modifyOrder(sellerorderid, "2", token) .subscribe(new Action1<String>() { @Override public void call(String s) { Toast.makeText(mContext, s, Toast.LENGTH_SHORT).show(); newOrderFragment.listOrder.clear(); newOrderFragment.pageindex = 1; newOrderFragment.requestData(); App.isNeedFreshData = true; App.isNeedFresShophData = true; } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { Toast.makeText(mContext, throwable.getMessage(), Toast.LENGTH_SHORT).show(); } }); } }); return view;}
其实ListView数据加载及数据缓存是比较复杂的,所以以后有机会还是要好好研读源码,这样才能有助于提升自己开发Android的性能和对Android工作的原理的理解。
- 关于 android listview 加载数据错位(错乱)问题
- android listview 数据加载错乱、错位、重复
- android listview 加载图片错乱(错位)(2)
- android listview 加载图片错乱(错位)
- listview 加载图片错乱(错位)
- 关于ListView数据错乱跟item上图片错位
- 【Android】ListView加载网络图片(解决图片错位问题)
- Android ListView加载图片错位的问题
- Android ListView异步加载图片错位问题
- 个人记录1-解决listview异步加载图片错位,滑动listview错乱抖动的问题
- android listview 含有edittext 数据错乱问题
- ListView数据错位问题
- android listview错乱问题
- 解决ListView加载错乱问题
- ListView图片加载错位问题
- android开发中解决ListView异步加载图片错位问题
- 解决Android ListView中图片异步加载错位问题
- Android ListView图片异步加载时,图片错位的问题
- java提高篇(九)-----详解匿名内部类
- android群英传笔记 surfaceView
- Android 使用Android Studio来生成SHA1以及MD5,还有包名
- Linux20个基础命令学习
- 王道计算机网络--2.1通信基础
- 关于 android listview 加载数据错位(错乱)问题
- java中int和integer比较,integer和integer比较
- 1030. Travel Plan
- 可靠传输之TCP协议
- spring cloud框架搭建
- java---Properties文件读写类
- Java源码分析之Arrays
- Oracle临时表空间综述
- SPI驱动:(Linux驱动7)