1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 关于 android listview 加载数据错位(错乱)问题

关于 android listview 加载数据错位(错乱)问题

时间:2020-09-14 22:04:23

相关推荐

关于 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缓存起来,避免重复加载耗费资源。

我自己的代码:

@OverridepublicView getView(intposition, View view, ViewGroup parent) {finalViewHolder mViewHolder;if(null== view){mViewHolder =newViewHolder();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 =newOrderGoodsListItemAdapter(mContext,listOrder.get(position).getOrderSeller().getLstOrderGoods());mViewHolder.listgoods.setAdapter(mOrderGoodsListItemAdapter);setListViewHeightOnChildren(mViewHolder.listgoods);final intindex = position;mViewHolder.btnOrderOk.setOnClickListener(newView.OnClickListener(){@Overridepublic voidonClick(View v) {String sellerorderid = String.valueOf(listOrder.get(index).getOrderSeller().getSellerorderid());String token = App.getInstance().sellerInfo.getToken();orderService.modifyOrder(sellerorderid,"1", token).subscribe(newAction1<String>() {@Overridepublic voidcall(String s) {Toast.makeText(mContext, s, Toast.LENGTH_SHORT).show();newOrderFragment.listOrder.clear();newOrderFragment.pageindex= 1;newOrderFragment.requestData();App.isNeedFreshData=true;App.isNeedFresShophData=true;}},newAction1<Throwable>() {@Overridepublic voidcall(Throwable throwable) {Toast.makeText(mContext, throwable.getMessage(), Toast.LENGTH_SHORT).show();}});}});mViewHolder.btnOrderCancel.setOnClickListener(newView.OnClickListener(){@Overridepublic voidonClick(View v) {String sellerorderid = String.valueOf(listOrder.get(index).getOrderSeller().getSellerorderid());String token = App.getInstance().sellerInfo.getToken();orderService.modifyOrder(sellerorderid,"2", token).subscribe(newAction1<String>() {@Overridepublic voidcall(String s) {Toast.makeText(mContext, s, Toast.LENGTH_SHORT).show();newOrderFragment.listOrder.clear();newOrderFragment.pageindex= 1;newOrderFragment.requestData();App.isNeedFreshData=true;App.isNeedFresShophData=true;}},newAction1<Throwable>() {@Overridepublic voidcall(Throwable throwable) {Toast.makeText(mContext, throwable.getMessage(), Toast.LENGTH_SHORT).show();}});}});view.setTag(mViewHolder);}else{mViewHolder = (ViewHolder) view.getTag();}returnview;}

然后问题就来了,当时我就”自作小聪明“或者说“没有注意”,觉得当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 中的数据必须每次都重新获取并加载。

修改后的代码:

@OverridepublicView getView(intposition, View view, ViewGroup parent) {finalViewHolder mViewHolder;if(null== view){mViewHolder =newViewHolder();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 =newOrderGoodsListItemAdapter(mContext,listOrder.get(position).getOrderSeller().getLstOrderGoods());mViewHolder.listgoods.setAdapter(mOrderGoodsListItemAdapter);setListViewHeightOnChildren(mViewHolder.listgoods);final intindex = position;mViewHolder.btnOrderOk.setOnClickListener(newView.OnClickListener(){@Overridepublic voidonClick(View v) {String sellerorderid = String.valueOf(listOrder.get(index).getOrderSeller().getSellerorderid());String token = App.getInstance().sellerInfo.getToken();orderService.modifyOrder(sellerorderid,"1", token).subscribe(newAction1<String>() {@Overridepublic voidcall(String s) {Toast.makeText(mContext, s, Toast.LENGTH_SHORT).show();newOrderFragment.listOrder.clear();newOrderFragment.pageindex= 1;newOrderFragment.requestData();App.isNeedFreshData=true;App.isNeedFresShophData=true;}},newAction1<Throwable>() {@Overridepublic voidcall(Throwable throwable) {Toast.makeText(mContext, throwable.getMessage(), Toast.LENGTH_SHORT).show();}});}});mViewHolder.btnOrderCancel.setOnClickListener(newView.OnClickListener(){@Overridepublic voidonClick(View v) {String sellerorderid = String.valueOf(listOrder.get(index).getOrderSeller().getSellerorderid());String token = App.getInstance().sellerInfo.getToken();orderService.modifyOrder(sellerorderid,"2", token).subscribe(newAction1<String>() {@Overridepublic voidcall(String s) {Toast.makeText(mContext, s, Toast.LENGTH_SHORT).show();newOrderFragment.listOrder.clear();newOrderFragment.pageindex= 1;newOrderFragment.requestData();App.isNeedFreshData=true;App.isNeedFresShophData=true;}},newAction1<Throwable>() {@Overridepublic voidcall(Throwable throwable) {Toast.makeText(mContext, throwable.getMessage(), Toast.LENGTH_SHORT).show();}});}});returnview;}

其实ListView数据加载及数据缓存是比较复杂的,所以以后有机会还是要好好研读源码,这样才能有助于提升自己开发Android的性能和对Android工作的原理的理解。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。