最新內容建議直接訪問原文:Android ListView滑動過程中圖片顯示重複錯亂閃爍問題解決
主要分析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的個數。
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圖片顯示閃爍
上面b的情況,第14行圖片又很快加載結束,所以我們看到第14行先顯示了第2行的圖片,立馬又顯示了自己的圖片進行覆蓋造成閃爍錯亂。
2、解決方法
通過上面的分析我們知道了出現錯亂的原因是異步加載及對象被複用造成的,如果每次getView能給對象一個標識,在異步加載完成時比較標識與當前行item的標識是否一致,一致則顯示,否則不做處理即可。
下面以使用ImageCache爲ListView提供圖片獲取緩存爲例,ListView中強烈推薦使用ImageCache。
首先在listview adapter的getView中添加
@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(); } …… // 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函數中添加
public void onImageLoaded(String imageUrl, Drawable imageDrawable, View view, boolean isInCache) { // can be another view child, like textView and so on if (view != null && imageDrawable != null) { ImageView imageView = (ImageView)view; // add tag judge, avoid listView cache and so on String imageUrlTag = (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.
其他異步加載過程解決原理類似。
你可能還感興趣:
Android公共庫(緩存 下拉ListView 下載管理Pro 靜默安裝 root運行 Java公共類)
Android系統下載管理DownloadManager功能介紹及使用示例