关于 android listview 加载数据错位(错乱)问题
一般的关于Adapter中getView的写法不外乎以下形式:
@Overridepublic
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缓存起来,避免重复加载耗费资源。
我自己的代码:
@Override public 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 中的数据必须每次都重新获取并加载。
修改后的代码:
@Override public 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 加载数据错位(错乱)问题相关推荐
- ListView加载图片错位的问题,解决很简单
能看到这片文章,相信你遇到了ListView获取RecycView加载数据,产生了错乱的情况, 最近项目遇到,需要动态根据服务器返回的图片链接,动态生成图片,并显示的问题, 结果就出现了图片错兰的问题 ...
- android progressbar 加载数据,ProgressBar的使用实例
以下内容有三方式设置进度条 设置一个简单的进度条 布局 android:id="@+id/progressBar" style="?android:attr/progre ...
- Android中ListView分页加载数据
熟悉Android的朋友们都知道,不管是微博客户端还是新闻客户端,都离不开列表组件,可以说列表组件是Android数据展现方面最重要的组件,我们今天就要讲一讲列表组件ListView加载数据的相关内容 ...
- [转]ListView滚动到底部自动加载数据
转自:http://blog.csdn.net/shineflowers/article/details/41744241 在Android中有很多时候会选择用ListView加载数据,有的是分批加载 ...
- android异步加载视频缩略图,Android 视频缩略图的缓存机制和异步加载
关注微信号:javalearns 随时随地学Java 或扫一扫 随时随地学Java 在这次的工作开发项目中,涉及到一个视频缩略图的视频列表:这个在大家看来,制作视频缩略图就是两行代码就搞定的事.确 ...
- android 之ListView分页效果以及从网络上加载数据一系列的综合运用
数据分页策略: <1>:用多少查多少 <2>:全部查询出来,再进行分页处理 数据分页的有关算法: (1):起始索引值 = (当前页-1)*每页显示的记录数 (2):结束索引值 ...
- Android Listview滑动时不加载数据,停下来时加载数据,让App更优
转载:http://blog.csdn.net/yy1300326388/article/details/45153813 数据源配置(Adapter) package com.zhengsongla ...
- android listview动态加载数据,ListView动态加载数据
当listview需要加载的数据过多时,若一次性载入则速度会相当缓慢,影响用户体验,这时候就需要动态加载数据,即每次载入固定长度的数据,android market的listview就是采用这种方式, ...
- Android开发之ContentProvider结合LoaderManager加载数据(图文源代码分享)
ContentProvider作为Android的四大存储方式之一,有着广泛的应用性,它暴露了数据地址,可以让其他应用访问数据,可以用于存储图片.通讯录等信息,这篇博文将详细介绍ContentProv ...
最新文章
- aix java home_在AIX环境下安装IBM JDK 1.6的教程
- MIT:睡眠不足会让你连路都走不好,但补觉还有救
- EXPLAIN 命令详解
- mysql主从 1050错误
- Multi thread: std::promise
- Jquery实现子菜单散开动画
- python random random_【python】random与numpy.random
- 管理感悟:维护每日工作列表
- 基于Python的旅游管理系统-小程序
- 学习记录 | ZigBee协议栈实践——串口收发数据
- BAT投资AI已超硅谷巨头,北京成风投增长第一城
- oppoa5降级教程_OPPO A5官方出厂rom系统刷机包下载_卡刷升级包降级回退包
- 对Autorun.inf类U盘病毒的攻防经验总结
- vue.js动态计时器_基于Vue.js的Pomodoro技术计时器
- python+flask+html/css+mysql+BAE 打造CSDN简历自动生成系统(附网站完全源码)
- 日语考级N1~N5各等级证书含金量如何,代表什么水平?有没有必要考?
- 系统稳定性(基于matlab求传递函数特征根)
- 广东省第四届“强网杯”网络安全大赛(“泄露的秘密WP”)
- 2022届秋招,从被拒到上岸 | 谈谈YK菌在2021年的经历与收获
- 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 HDU - 2191