关于 android listview 加载数据错位(错乱)问题
一般的關于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緩存起來,避免重復加載耗費資源。
我自己的代碼:
@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的注釋:
解決方法
所以唯一的解決方法就是只在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 加载数据错位(错乱)问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国移动与高通联合 vivo、小米等完成
- 下一篇: android 格式格式:YYYYMM