universal image loader在listview/gridview中滾動(dòng)時(shí)重復(fù)加載圖片的問題及解決方法

原文轉(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ā)過程中省不少事,不過如果想用好也需要自己真正的去研究下

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容