編輯: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.
其他異步加載過程解決原理類似。
使用Android系統最大的優點就是刷機,並且良好的兼容性和自由的可擴展性成為開發者的“樂土”,比如CM等自定義ROM,那麼你有沒有想過將Andr
通過手機的通知系統,可以將應用程序的一些重要消息告知給用戶。流暢、 舒適、友好的應用程序離不開精心設計的消息提醒機制。但是並不是所有的通知 都是用戶想看的,否則只會給用戶
ionic第二坑——ionic 上拉菜單(ActionSheet)安卓樣式坑閒話不說,先上圖: 這是IOS上的顯示效果,代碼如下: HTML部分: 1 <bod
盡管以前你也可以將一個網頁放到Android主屏直接啟動,但Chrome V31 beta for Android加到主屏的功能稍微有點改進,就是通過快捷方式進入的網頁是