原文轉(zhuǎn)載:http://www.cnblogs.com/wuxilin/p/4333241.html
在listview/gridview中使用UIL來display每個(gè)item的圖片,當(dāng)圖片數(shù)量較多需要滑動(dòng)滾動(dòng)時(shí)會(huì)出現(xiàn)卡頓,而且加載過的圖片再次上翻后依然會(huì)重復(fù)加載(顯示設(shè)置好的加載中圖片)
最近在使用UIL遇到了這個(gè)問題,相信這個(gè)問題許多使用UIL的人都碰到過
現(xiàn)在把解決方法貼出來給有同樣問題的朋友做參考
先看下UIL的工作流程
在已經(jīng)允許內(nèi)存,存儲(chǔ)卡緩存的前提下,當(dāng)一個(gè)圖片被請(qǐng)求display時(shí),首先要判斷圖片是否緩存在內(nèi)存中,如果false則嘗試從存儲(chǔ)卡讀取,如果依然不存在最后才從網(wǎng)絡(luò)地址下載
從內(nèi)存讀取的速度最快,存儲(chǔ)卡次之,在我們滾動(dòng)listview的時(shí)候,如果是從內(nèi)存加載圖片則會(huì)顯得非常流暢,如果是存儲(chǔ)卡就會(huì)先出現(xiàn)載入中圖片然后再顯示實(shí)際圖片
我們通常認(rèn)為已經(jīng)讀過一次的圖片自然將會(huì)加入內(nèi)存緩存中,那么下一次讀取將是直接從內(nèi)存中讀取,但是實(shí)際上載入過的圖片在滑動(dòng)出屏幕再滑動(dòng)回來后依然會(huì)再次從存儲(chǔ)卡讀取,這主要是UIL的緩存策略引起的一個(gè)"疑似BUG"
查看UIL的源碼,displayImage函數(shù)
public void displayImage(String uri, ImageView imageView, DisplayImageOptions options) {
displayImage(uri,newImageViewAware(imageView), options,null,null);
}
會(huì)有ImageAware接口的一個(gè)實(shí)例化,這個(gè)默認(rèn)的實(shí)例化有個(gè)重要的參數(shù) :checkActualViewSize 具體說明如下
public ViewAware(View view) {
this(view,true);
}
/**
* Constructor
*
*@param view{@linkandroid.view.View View} to work with
*@param checkActualViewSize true - then {@link#getWidth()} and {@link#getHeight()} will check actual
*size of View. It can cause known issues like
*this.
*But it helps to save memory because memory cache keeps bitmaps of actual (less in
*general) size.
*
*false - then {@link#getWidth()} and {@link#getHeight()} will NOT
*consider actual size of View, just layout parameters.
If you set 'false'*it's recommended 'android:layout_width' and 'android:layout_height' (or
*'android:maxWidth' and 'android:maxHeight') are set with concrete values. It helps to
*save memory.
*/
public ViewAware(View view,boolean checkActualViewSize) {
if(view ==null)throw new IllegalArgumentException("view must not be null");
this.viewRef =new WeakReference(view);
this.checkActualViewSize = checkActualViewSize;
}
這個(gè)參數(shù)會(huì)影響緩存時(shí)的key名稱,當(dāng)圖片第一次緩存時(shí),當(dāng)時(shí)圖片并未下載,自然無法獲得圖片的長(zhǎng)寬尺寸,這時(shí)UIL會(huì)使用配置預(yù)設(shè)的maxwidth和maxheight為長(zhǎng)寬,緩存的key名稱為類似這樣:url_widthxheight
在checkActualViewSize設(shè)置為true時(shí),第二次載入圖片的view將會(huì)讀取view的長(zhǎng)寬,這時(shí)的長(zhǎng)寬會(huì)是圖片的實(shí)際尺寸,相應(yīng)的生成的緩存key名稱也會(huì)變成url_realwidthxrealheight,這個(gè)名稱同之前緩存的不同,因此也當(dāng)然不能在緩存查詢中命中
所以最后就需要再次從存儲(chǔ)中加載圖片,并以新的keyname再存一份副本到內(nèi)存中
解決方法有兩個(gè):
1)設(shè)置imageview的layout_width和layout_height為實(shí)際圖片長(zhǎng)寬(假如你的圖片都是固定尺寸的,這樣做就OK了)
2)display的方法修改一下,不直接display imageview改為ImageAware,類似
ImageAware imageAware =new ImageViewAware(imageView,false);
imageLoader.displayImage(imageUri, imageAware);
顯式的將checkActualViewSize設(shè)為false, 這樣圖片的緩存也將只會(huì)保存一個(gè)副本,保證第二次查詢時(shí)可以直接命中
按上述方法設(shè)置之后一般來說在listview/gridview滑動(dòng)時(shí)圖片效果基本沒什么大問題了,但是還有些額外設(shè)置也許也是大家需要注意的
首先是config的初始化
File cacheDir = StorageUtils.getOwnCacheDirectory(getApplicationContext(), "imageloader/Cache");//緩存文件的存放地址
ImageLoaderConfiguration config =new ImageLoaderConfiguration
.Builder(getApplicationContext())
.memoryCacheExtraOptions(480, 800)// max width, max height
.threadPoolSize(3)//線程池內(nèi)加載的數(shù)量
.threadPriority(Thread.NORM_PRIORITY - 2)//降低線程的優(yōu)先級(jí)保證主UI線程不受太大影響
.denyCacheImageMultipleSizesInMemory()
.memoryCache(newLruMemoryCache(5 * 1024 * 1024))//建議內(nèi)存設(shè)在5-10M,可以有比較好的表現(xiàn)
.memoryCacheSize(5 * 1024 * 1024)
.discCacheSize(50 * 1024 * 1024)
.discCacheFileNameGenerator(newMd5FileNameGenerator())
.tasksProcessingOrder(QueueProcessingType.LIFO)
.discCacheFileCount(100)//緩存的文件數(shù)量
.discCache(newUnlimitedDiscCache(cacheDir))
.defaultDisplayImageOptions(DisplayImageOptions.createSimple())
.imageDownloader(newBaseImageDownloader(getApplicationContext(), 5 * 1000, 30 * 1000))// connectTimeout (5 s), readTimeout (30 s)
.writeDebugLogs()// Remove for release app
.build();
然后是option的設(shè)置
options =new DisplayImageOptions.Builder()
.showStubImage(R.drawable.default_cover)
.showImageForEmptyUri(R.drawable.default_cover)
.showImageOnFail(R.drawable.default_cover)
.cacheInMemory(true)
.cacheOnDisc(true)
.imageScaleType(ImageScaleType.NONE)
.bitmapConfig(Bitmap.Config.RGB_565)//設(shè)置為RGB565比起默認(rèn)的ARGB_8888要節(jié)省大量的內(nèi)存
.delayBeforeLoading(100)//載入圖片前稍做延時(shí)可以提高整體滑動(dòng)的流暢度
.build();
滑動(dòng)時(shí)禁止加載也可以有效的提高表現(xiàn)
setOnScrollListener(new PauseOnScrollListener(imageLoader,true,true));//兩個(gè)分別表示拖動(dòng)下拉條和滑動(dòng)過程中暫停加載
最后就是在getview中,例行的viewholder保存狀態(tài)之外,將URL存入imageview的tag中,通過對(duì)比URL值來減少UIL的display次數(shù)以提高表現(xiàn)
UIL是個(gè)非常不錯(cuò)的圖片加載類的第三方庫,可以幫我們?cè)陂_發(fā)過程中省不少事,不過如果想用好也需要自己真正的去研究下