Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android第三方資源使用之ImageCache

Android第三方資源使用之ImageCache

編輯:關於android開發

Android第三方資源使用之ImageCache


 

我們常用的諸如ImageLoader Picasso 都有類似的效果,今天上的是國內大牛Trinea的ImageCache,那為什麼用他的這個呢?

個人覺得他更輕量級,效果簡單明了,一些衍生和伸展性做的也還不錯。


一.說之前,還是說一下一些比較重要的知識點。(我們不生產知識,我們只是知識的搬運工)

緩存:java的對象創建需要分配資源較耗費時間,加上創建的對象越多會造成越頻繁的gc影響系統響應。主要使用單例模式、緩存(圖片緩存、線程池、View緩存、IO緩存、消息緩存、通知欄notification緩存)及其他方式減少對象創建。

然後緩存中,又圖片緩存、線程池、View緩存、IO緩存、消息緩存、通知欄notification緩存等。(這不是我們主要講的內容,不知道可以自己Google,這裡只是例舉下)

那麼,在實用場景下會有哪些常見的異步加載問題呢?

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行的圖片,立馬又顯示了自己的圖片進行覆蓋造成閃爍錯亂

因為,如果我們用 Back鍵回到上一個Activity再進來的時候是不是還要重新加載?或者我第一次加載存到本地,第二次再讀本地IO?所以,緩存成為提高用戶體驗和節約性能一個很好的途徑。


二.ImageCache

ImageCache有什麼優勢呢?

(1). 使用簡單 (2). 輕松獲取及預取新圖片 (3). 包含二級緩存 (4). 可選擇多種緩存算法(FIFO、LIFO、LRU、MRU、LFU、MFU等13種)或自定義緩存算法 (5). 可方便的保存及初始化恢復數據 (6). 支持文件sd卡保存及自定義文件名規則 (7). 省流量性能佳(有且僅有一個線程獲取圖片) (8). 支持不同類型網絡處理 (9). 可根據系統配置初始化緩存 (10). 擴展性強 (11). 支持等待隊列 (12). 包含map的大多數接口。

-1.使用:

a.初始化一個ImageCache 對象

public static final ImageCache IMAGE_CACHE = CacheManager.getImageCache();

b.需要加載圖片的地方調用get(String imageUrl, View view)異步加載圖片

IMAGE_CACHE.get(imageUrl, imageView);

就是辣麼簡單,效果就能達到。

當然,對緩存,線程等等等一系列有要求的,也可以加以設置:

/** image cache **/
public static final ImageCache IMAGE_CACHE = new ImageCache();

static {
    OnImageCallbackListener imageCallBack = new OnImageCallbackListener() {

        private static final long serialVersionUID = 1L;

        // callback function before get image, run on ui thread
        @Override
        public void onPreGet(String imageUrl, View view) {
            // Log.e(TAG_CACHE, pre get image);
        }

        // callback function after get image successfully, run on ui thread
        @Override
        public void onGetSuccess(String imageUrl, Bitmap loadedImage, View view, boolean isInCache) {
            // can be another view child, like textView and so on
            if (view != null && loadedImage != null && view instanceof ImageView) {
                ImageView imageView = (ImageView)view;
                imageView.setImageBitmap(loadedImage);
            }
        }

        // callback function after get image failed, run on ui thread
        @Override
        public void onGetFailed(String imageUrl, Bitmap loadedImage, View view, FailedReason failedReason) {
            Log.e(TAG_CACHE, new StringBuilder(128).append(get image ).append(imageUrl).append( error)
                                                   .toString());
        }

        @Override
        public void onGetNotInCache(String imageUrl, View view) {

        }
    };
    IMAGE_CACHE.setOnImageCallbackListener(imageCallBack);
}

-2.功能

(1) 多種構造函數,可根據系統配置初始化緩存
public ImageCache()
public ImageCache(int primaryCacheMaxSize)
public ImageCache(int primaryCacheMaxSize, int secondaryCacheMaxSize)
public ImageCache(int primaryCacheMaxSize, int primaryCacheThreadPoolSize, int secondaryCacheMaxSize, int secondaryCacheThreadPoolSize)
支持四種構造函數,支持一級和二級緩存大小及獲取圖片線程池大小的設置。默認會根據系統可用內存大小設置緩存大小,根據系統Cpu個數設置線程池大小。

(2)、獲取圖片及自動預取
get(String imageUrl, View view)異步獲取圖片,在圖片獲取成功後自動調用OnImageCallbackListener的onGetSuccess函數,返回是否已在緩存中
get(String imageUrl, List urlList, View view)異步獲取圖片,在圖片獲取成功後自動調用OnImageCallbackListener的onGetSuccess函數,並且根據imageUrl在urlList中的位置向前向後預取圖片,返回是否已在緩存中。

public void setForwardCacheNumber(int forwardCacheNumber) 向前預取圖片個數設置,默認為PreloadDataCache#DEFAULT_FORWARD_CACHE_NUMBER
public void setBackwardCacheNumber(int backwardCacheNumber)向後預取圖片個數設置默認,默認為PreloadDataCache#DEFAULT_BACKWARD_CACHE_NUMBER

public CacheObject get(K key)
public CacheObject get(K key, List keyList)
兩個接口是直接同步獲取圖片,且獲取成功後不會調用OnImageCallbackListener的onGetSuccess函數

(3)、設置緩存算法
setCacheFullRemoveType(CacheFullRemoveType cacheFullRemoveType)
設置緩存算法,緩存算法即為緩存滿時為了插入新數據,刪除舊數據的規則。

目前包括FIFO、LIFO、LRU、MRU、LFU、MFU、優先級低先刪除、優先級高先刪除、數據小先刪除、數據大先刪除、圖片小先刪除、圖片大先刪除、永不刪除。還可以通過實現CacheFullRemoveType來自定義緩存算法。。默認為RemoveTypeUsedCountSmall,即LRU使用頻率低先刪除。下面詳細介紹各個算法:
RemoveTypeEnterTimeFirst FIFO先進先出,先進入先刪除
RemoveTypeEnterTimeLast LIFO後進先出,後進入先刪除
RemoveTypeLastUsedTimeFirst LRU(Least Recently User),最先使用先刪除
RemoveTypeLastUsedTimeLast MRU(Most Recently Used),最近使用先刪除
RemoveTypeUsedCountSmall LFU(Least Frequently Used),使用頻率低先刪除
RemoveTypeUsedCountBig MRU(Most Frequently Used),使用頻率高先刪除
RemoveTypePriorityLow 優先級低先刪除
RemoveTypePriorityHigh 優先級低先刪除
RemoveTypeBitmapSmall 圖片小的先刪除
RemoveTypeBitmapLarge 圖片大的先刪除
RemoveTypeDataBig 數據大先刪除,根據緩存數據的compareTo函數決定
RemoveTypeDataSmall 數據小先刪除,根據緩存數據的compareTo函數決定
RemoveTypeNotRemove 不刪除,緩存滿時不再允許插入新數據

自定義緩存算法只需要實現CacheFullRemoveType的compare方法即可。比較結果小於0表示會被先刪除

public class RemoveTypePriorityHigh implements CacheFullRemoveType {

    private static final long serialVersionUID = 1L;

    @Override
    public int compare(CacheObject obj1, CacheObject obj2) {
        return (obj2.getPriority() > obj1.getPriority()) ? 1 : ((obj2.getPriority() == obj1.getPriority()) ? 0 : -1);
    }
}

(4)、保存及初始化恢復數據
public boolean saveDataToDb(Context context, String tag)
保存數據到數據庫,可在程序退出時調用,不建議在每個activity onDestrory時調用,而是整個程序退出(比如”退出確認對話框”點擊確認)時,見本文3.1常見問題解答。
public void initData(Context context, String tag)
初始化恢復數據,可在程序剛開始加載時調用,不建議在每個activity oncreate調用,而是整個程序初始化(比如Application的onCreate函數)時,見本文3.1常見問題解答。

(5)、是否啟用隊列
setOpenWaitingQueue(boolean isOpenWaitingQueue)
當不同view通過get函數獲取圖片時,是否開啟等待隊列。
若開啟,保存所有view,圖片獲取成功後依次調用OnImageCallbackListener的onGetSuccess函數;否則僅保存最後調用get的view,圖片獲取成功後調用OnImageCallbackListener的onGetSuccess函數
默認開啟隊列等待。如果希望最優性能且場景滿足,可設置為false。

(6)、設置圖片獲取方式接口
setOnGetDataListener(OnGetDataListener

setOnGetDataListener(ImageCacheManager.getImageFromSdcardListener());

注意這種方式compressListener是無效的,如果希望利用compressListener,可以如下設置:

setOnGetDataListener(new OnGetDataListener() {

    private static final long serialVersionUID = 1L;

    @Override
    public CacheObject onGetData(String imagePath) {
        if (!FileUtils.isFileExist(imagePath)) {
            return null;
        }

        CompressListener compressListener = IMAGE_CACHE.getCompressListener();
        int compressSize = 0;
        if (compressListener != null) {
            compressSize = compressListener.getCompressSize(imagePath);
        }
        Bitmap bm;
        if (compressSize > 1) {
            BitmapFactory.Options option = new BitmapFactory.Options();
            option.inSampleSize = compressSize;
            bm = BitmapFactory.decodeFile(imagePath, option);
        } else {
            bm = BitmapFactory.decodeFile(imagePath);
        }
        return (bm == null ? null : new CacheObject(bm));
    }
});

5、內存溢出OOM問題?
通過setCompressListener接口壓縮圖片,getCompressSize返回值為圖片長寬縮放比例,同BitmapFactory.Options#inSampleSize


2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
IMAGE_CACHE.setCompressListener(new CompressListener() {

    @Override
    public int getCompressSize(String imagePath) {
        if (FileUtils.isFileExist(imagePath)) {
            long fileSize = FileUtils.getFileSize(imagePath) / 1000;
            /**
             * if image bigger than 100k, compress to 1/(n + 1) width and 1/(n + 1) height, n is fileSize / 100k
             **/
            if (fileSize > 100) {
                return (int)(fileSize / 100) + 1;
            }
        }
        return 1;
    }
});

還可見 圖片OutOfMemory異常bitmap size exceeds VM budget的原因及解決方法

更多內容可以在作者的文檔中找到。

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved