日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發(fā)布時(shí)間:2023/12/19 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 关于 android listview 加载数据错位(错乱)问题 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一般的關(guān)于Adapter中g(shù)etView的寫法不外乎以下形式:

@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源碼中關(guān)于getView方法的實(shí)現(xiàn)就是采用的以上形式,如ArrayAdapter等。因?yàn)檫@種寫法的好處也是顯而易見的,如果該position的convertview曾經(jīng)被加載過,在數(shù)據(jù)集合未被改動(dòng)的前提下,系統(tǒng)會(huì)自動(dòng)將該position的convertview緩存起來,避免重復(fù)加載耗費(fèi)資源。

我自己的代碼:

@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; }

然后問題就來了,當(dāng)時(shí)我就”自作小聰明“或者說“沒有注意”,覺得當(dāng)convertview==null時(shí)只是做了item布局的加載以及相關(guān)控件ID的綁定操作,為什么連內(nèi)容的加載操作也放入其中呢,這樣下次加載緩存是就省去內(nèi)容set的操作了,然后就出現(xiàn)了滑動(dòng)ListView后數(shù)據(jù)顯示錯(cuò)位的問題。


剖析原因:

后來看源碼發(fā)現(xiàn),原來AbListView中獲取getView()和滑動(dòng)操作是異步進(jìn)行的,其中滑動(dòng)操作在一個(gè)FlingRunnable的支線程中運(yùn)行,所以這就導(dǎo)致了在ListView在滑動(dòng)時(shí)可能已經(jīng)滑動(dòng)到了第十行,但可能第二行的數(shù)據(jù)這時(shí)就被直接使用了,這就是導(dǎo)致數(shù)據(jù)加載錯(cuò)亂的根本原因。
附上源碼中對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 中的數(shù)據(jù)必須每次都重新獲取并加載。

修改后的代碼:

@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; }

其實(shí)ListView數(shù)據(jù)加載及數(shù)據(jù)緩存是比較復(fù)雜的,所以以后有機(jī)會(huì)還是要好好研讀源碼,這樣才能有助于提升自己開發(fā)Android的性能和對Android工作的原理的理解。

總結(jié)

以上是生活随笔為你收集整理的关于 android listview 加载数据错位(错乱)问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。