Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android系統教程 >> Android開發教程 >> Android ListView滑動過程中圖片顯示重復錯亂閃爍的原因及解決方法

Android ListView滑動過程中圖片顯示重復錯亂閃爍的原因及解決方法

編輯:Android開發教程

主要分析Android ListView滾動過程中圖片顯示重復、錯亂、閃爍的原因及解決方法,順帶提及ListView的緩存機制。

1、原因分析

ListView item緩存機制:為了使得性能更優,ListView會緩存行item(某行對應的View)。ListView通過adapter的getView函數獲得每行的item。滑動過程中,

a. 如果某行item已經滑出屏幕,若該item不在緩存內,則put進緩存,否則更新緩存;

b. 獲取滑入屏幕的行item之前會先判斷緩存中是否有可用的item,如果有,做為convertView參數傳遞給adapter的getView。

更具體可見源代碼ListView.obtainView。

這樣,如下的getView寫法就可以充分利用緩存大大提升ListView的性能。即便上萬個行item,最多inflate的次數為n,n為一屏最多顯示ListView 行item的個數。

@Override
public 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 [email protected] 2013-08-01
*/
private static class ViewHolder {
     
    ImageView appIcon;
    TextView  appName;
    TextView  appInfo;
}

這樣提升了性能,但同時也會造成另外一些問題:

a. 行item圖片顯示重復

這個顯示重復是指當前行item顯示了之前某行item的圖片。

比如ListView滑動到第2行會異步加載某個圖片,但是加載很慢,加載過程中listView已經滑動到了第14行,且滑動過程中該圖片加載結束,第2行已不在屏幕內,根據上面介紹的緩存原理,第2行的view可能被第14行復用,這樣我們看到的就是第14行顯示了本該屬於第2行的圖片,造成顯示重復。

b. 行item圖片顯示錯亂

這個顯示錯亂是指某行item顯示了不屬於該行item的圖片。

比如ListView滑動到第2行會異步加載某個圖片,但是加載很慢,加載過程中listView已經滑動到了第14行,第2行已不在屏幕內,根據上面介紹的緩存原理,第2行的view可能被第14行復用,第14行顯示了第2行的View,這時之前的圖片加載結束,就會顯示在第14行,造成錯亂。

c. 行item圖片顯示閃爍

查看本欄目更多精彩內容:http://www.bianceng.cn/OS/extra/

上面b的情況,第14行圖片又很快加載結束,所以我們看到第14行先顯示了第2行的圖片,立馬又顯示了自己的圖片進行覆蓋造成閃爍錯亂。

2、解決方法

通過上面的分析我們知道了出現錯亂的原因是異步加載及對象被復用造成的,如果每次getView能給對象一個標識,在異步加載完成時比較標識與當前行item的標識是否一致,一致則顯示,否則不做處理即可。

下面以使用ImageCache為ListView提供圖片獲取緩存為例,ListView中強烈推薦使用ImageCache。

首先在listview adapter的getView中添加

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

其中setTag表示設置標識,方便下面進行標志比對

if (!Cache.ICON_CACHE.get(imageUrl, imageView))

Cache.ICON_CACHE為ImageCache的實例,表示如果不在緩存內則設置drawable為null(當然你可以可以設置為你自己的默認資源),防止顯示了之前某個行item的圖片,解決了a. 行item圖片顯示重復問題。

在ImageCache的OnImageCallbackListener的onImageLoaded函數中添加

publicvoidonImageLoaded(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();取得之前設置的tag,然後和當前的url進行比較,如果相等則顯示,解決了b. 行item圖片顯示錯亂,c. 行item圖片顯示錯亂的兩個問題。其中ObjectUtils可見ObjectUtils@Github.

其他異步加載過程解決原理類似。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved