編輯:關於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的個數。
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 [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圖片顯示閃爍
上面b的情況,第14行圖片又很快加載結束,所以我們看到第14行先顯示了第2行的圖片,立馬又顯示了自己的圖片進行覆蓋造成閃爍錯亂。
2、解決方法
通過上面的分析我們知道了出現錯亂的原因是異步加載及對象被復用造成的,如果每次getView能給對象一個標識,在異步加載完成時比較標識與當前行item的標識是否一致,一致則顯示,否則不做處理即可。
下面以使用ImageCache為ListView提供圖片獲取緩存為例,ListView中強烈推薦使用ImageCache。
首先在listview adapter的getView中添加
其中setTag表示設置標識,方便下面進行標志比對
1if (!Cache.ICON_CACHE.get(imageUrl, imageView))Cache.ICON_CACHE為ImageCache的實例,表示如果不在緩存內則設置drawable為null(當然你可以可以設置為你自己的默認資源),防止顯示了之前某個行item的圖片,解決了a. 行item圖片顯示重復問題。
在ImageCache的OnImageCallbackListener的onImageLoaded函數中添加
Java 1 2 3 4 5 6 7 8 9 10 11 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.
其他異步加載過程解決原理類似。
在Android開發中,我們不可避免的會做到注冊功能,而現在的注冊大多數都是用手機去注冊的,那麼注冊的時候都會要求用獲取驗證碼的方式去驗證,我們接下來就來實戰一下自定義獲
在用到支付類app時,都有一個簡密的輸入框。。開始實現的時候思路有點問題,後來到github上搜了下,找到了一個開源的庫看起來相當的牛逼,,來個地址先:https://g
前言 在H5火熱的時代,許多框架都出了底部彈窗的控件,在H5被稱為彈出菜單ActionSheet,今天我們也來模仿一個ios的底部彈窗,取材於蘋果QQ的選擇頭像功能正文
這篇文章拖了好久了,一直存在草稿箱裡沒有繼續寫,趁今天有空,撸撸完。回想一下,你剛剛學習Android的時候,總會看到一些書上寫著,Android使用的是MVC模式,Ac