Android在ListView滑动数据混乱
我相信做過Android應(yīng)用程序開發(fā)或多或少都遇到了這個(gè)問題。或者是在ListView數(shù)據(jù)損壞幻燈片事件。要么GridView數(shù)據(jù)損壞幻燈片事件。
讓我們來看看一個(gè)網(wǎng)友寫的文章,個(gè)人感覺還不錯(cuò)的文章:
Android ListView滑動(dòng)過程中圖片顯示反復(fù)錯(cuò)位閃爍問題解決
主要分析Android ListView滾動(dòng)過程中圖片顯示反復(fù)、錯(cuò)亂、閃爍的原因及解決方法,順帶提及ListView的緩存機(jī)制。
1、原因分析
ListView item緩存機(jī)制:為了使得性能更優(yōu)。ListView會(huì)緩存行item(某行相應(yīng)的View)。ListView通過adapter的getView函數(shù)獲得每行的item。滑動(dòng)過程中,
a. 假設(shè)某行item已經(jīng)滑出屏幕,若該item不在緩存內(nèi),則put進(jìn)緩存,否則更新緩存。
b. 獲取滑入屏幕的行item之前會(huì)先推斷緩存中是否有可用的item,假設(shè)有,做為convertView參數(shù)傳遞給adapter的getView。
更詳細(xì)可見源代碼ListView.obtainView。
?
這樣,例如以下的getView寫法就能夠充分利用緩存大大提升ListView的性能。即便上萬個(gè)行item。最多inflate的次數(shù)為n,n為一屏最多顯示ListView 行item的個(gè)數(shù)。
ListView Adapter getView寫法 Java| 123456789101112131415161718192021222324 | @Overridepublic View getView(int position, View convertView, ViewGroup parent) {????ViewHolder holder;????if (convertView == null) {????????convertView = inflater.inflate(R.layout.list_item, null);????????holder = new ViewHolder();????????……????????convertView.setTag(holder);????} else {????????holder = (ViewHolder)convertView.getTag();????}}/** * ViewHolder * * @author trinea@trinea.cn 2013-08-01 */private static class ViewHolder {????ImageView appIcon;????TextView??appName;????TextView??appInfo;} |
這樣提升了性能。但同一時(shí)候也會(huì)造成另外一些問題:
a. 行item圖片顯示反復(fù)
這個(gè)顯示反復(fù)是指當(dāng)前行item顯示了之前某行item的圖片。
比方ListView滑動(dòng)到第2行會(huì)異步載入某個(gè)圖片,可是載入非常慢,載入過程中l(wèi)istView已經(jīng)滑動(dòng)到了第14行,且滑動(dòng)過程中該圖片載入結(jié)束。第2行已不在屏幕內(nèi),依據(jù)上面介紹的緩存原理,第2行的view可能被第14行復(fù)用,這樣我們看到的就是第14行顯示了本該屬于第2行的圖片。造成顯示反復(fù)。
?
b. 行item圖片顯示錯(cuò)亂
這個(gè)顯示錯(cuò)亂是指某行item顯示了不屬于該行item的圖片。
比方ListView滑動(dòng)到第2行會(huì)異步載入某個(gè)圖片。可是載入非常慢。載入過程中l(wèi)istView已經(jīng)滑動(dòng)到了第14行。第2行已不在屏幕內(nèi)。依據(jù)上面介紹的緩存原理,第2行的view可能被第14行復(fù)用,第14行顯示了第2行的View,這時(shí)之前的圖片載入結(jié)束,就會(huì)顯示在第14行,造成錯(cuò)亂。
?
c. 行item圖片顯示閃爍
上面b的情況,第14行圖片又非常快載入結(jié)束。所以我們看到第14行先顯示了第2行的圖片,立刻又顯示了自己的圖片進(jìn)行覆蓋造成閃爍錯(cuò)亂。
?
2、解決方法
通過上面的分析我們知道了出現(xiàn)錯(cuò)亂的原因是異步載入及對(duì)象被復(fù)用造成的。假設(shè)每次getView能給對(duì)象一個(gè)標(biāo)識(shí),在異步載入完畢時(shí)比較標(biāo)識(shí)與當(dāng)前行item的標(biāo)識(shí)是否一致,一致則顯示,否則不做處理就可以。
以下以使用ImageCache為ListView提供圖片獲取緩存為例,ListView中強(qiáng)烈推薦使用ImageCache。
首先在listview adapter的getView中加入
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | @Override publicViewgetView(intposition,ViewconvertView,ViewGroupparent){ ????ViewHolderholder; ????if(convertView==null){ ????????convertView=inflater.inflate(R.layout.list_item,null); ????????holder=newViewHolder(); ????????…… ????????convertView.setTag(holder); ????}else{ ????????holder=(ViewHolder)convertView.getTag(); ????} ????…… ????// add tag for image, to compare it when image loaded finish ????imageView.setTag(imageUrl); ????// if not in cache, restore default ????if(!Cache.ICON_CACHE.get(imageUrl,imageView)){ ????????imageView.setImageDrawable(null); ????} } |
當(dāng)中setTag表示設(shè)置標(biāo)識(shí),方便以下進(jìn)行標(biāo)志比對(duì)
| 1 | if (!Cache.ICON_CACHE.get(imageUrl, imageView)) |
Cache.ICON_CACHE為ImageCache的實(shí)例。表示假設(shè)不在緩存內(nèi)則設(shè)置drawable為null(當(dāng)然你能夠能夠設(shè)置為你自己的默認(rèn)資源),防止顯示了之前某個(gè)行item的圖片,攻克了a. 行item圖片顯示反復(fù)問題。
?
在ImageCache的OnImageCallbackListener的onGetSuccess函數(shù)中加入
Java| 1 2 3 4 5 6 7 8 9 10 11 | publicvoidonGetSuccess(StringimageUrl,DrawableimageDrawable,Viewview,booleanisInCache){ ????// can be another view child, like textView and so on ????if(view!=null&&imageDrawable!=null){ ????????ImageViewimageView=(ImageView)view; ????????// add tag judge, avoid listView cache and so on ????????StringimageUrlTag=(String)imageView.getTag(); ????????if(ObjectUtils.isEquals(imageUrlTag,imageUrl)){ ????????????imageView.setImageDrawable(imageDrawable); ????????} ????} }; |
在上面用String imageUrlTag = (String)imageView.getTag();取得之前設(shè)置的tag,然后和當(dāng)前的url進(jìn)行比較,假設(shè)相等則顯示,攻克了b. 行item圖片顯示錯(cuò)亂。c. 行item圖片顯示錯(cuò)亂的兩個(gè)問題。
當(dāng)中ObjectUtils可見ObjectUtils@Github.
其它異步載入過程解決原理類似。
插一句:標(biāo)題上我加了此文章的原文鏈接。
(1)把上文中if(convertView==null){}else{holder=(ViewHolder)convertView.getTag()?}給凝視 掉,然后數(shù)據(jù)混亂的問題就得以攻克了,可是這樣問題盡管攻克了,應(yīng)用程序性能就減少了。顯然此種方法雖能解決這個(gè)問題,可是還是不建議使用。
(2)就是通過加入Tag標(biāo)記,可是盡管是說加入Tag標(biāo)記,每個(gè)應(yīng)用程序加入Tag的方法不同。故在此無法給出一個(gè)統(tǒng)一的解決方法,僅僅能說一個(gè)統(tǒng)一的解決思路。比如:假設(shè)混亂的是一件商品的數(shù)量,能夠把商品的數(shù)量暫時(shí)存到一個(gè)數(shù)組中,然后每次取值都從數(shù)組里取值即可了。事實(shí)上說白了,就是依據(jù)詳細(xì)的情況new 一個(gè)對(duì)應(yīng)的數(shù)組,來做數(shù)據(jù)的中轉(zhuǎn)站。例如以下圖情形:
在滑動(dòng)時(shí),我們會(huì)發(fā)現(xiàn)數(shù)量的值會(huì)發(fā)生混亂,或者在加減右圖中的數(shù)字時(shí),也會(huì)出現(xiàn)這種情況。
以下提供一個(gè)類似的方案。事實(shí)上對(duì)應(yīng)的代碼都是在你應(yīng)用中的Adapter中改動(dòng)。
首先聲明一個(gè)數(shù)組用于存放數(shù)量:
private int [] tempNum;
然后在本Adapter的構(gòu)造方法中初始化此數(shù)組:tempNum=new int[this.list.size()];
然后在getView方法中一定要有例如以下代碼:mItemViewHolder.mTvNum.setTag(position);
mItemViewHolder.mTvNum.setText(tempNum[position]+"");
然后在加減時(shí)。也要把最新的數(shù)量存到數(shù)組里。例如以下:
<span style="white-space:pre"> </span>case R.id.menu_reduce_iv:mTextView=(TextView)v.getTag(R.id.menu_num_tv);num=Integer.valueOf(mTextView.getText().toString().trim());num--;tempNum[(Integer)mTextView.getTag()]=num;if(num<0){Toast.makeText(context, "親,不能再減了,趕緊加加吧。", Toast.LENGTH_SHORT).show();}else{mTextView.setText( tempNum[(Integer)mTextView.getTag()]+"");}break;case R.id.menu_add_iv:mTextView=(TextView)v.getTag(R.id.menu_num_tv);num=Integer.valueOf(mTextView.getText().toString().trim());num++;tempNum[(Integer)mTextView.getTag()]=num;mTextView.setText(tempNum[(Integer)mTextView.getTag()]+"");break;
總之。在做此類處理時(shí),一定要new一個(gè)數(shù)組,然后在混亂的地方一定要setTag。
大致就說到這里,鄙人才疏學(xué)淺,有不正確之處,望大家及時(shí)指出。轉(zhuǎn)載請(qǐng)注明:http://blog.csdn.net/android_jiangjun/article/details/39924541
版權(quán)聲明:本文博客原創(chuàng)文章,博客,未經(jīng)同意,不得轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的Android在ListView滑动数据混乱的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux下搭建SVN+版本冲突
- 下一篇: bzoj 2748: [HAOI2012