天天看點

【android】實作圖檔的三級緩存。工具類

本文主要分析以下幾點

  • 為什麼使用三級緩存
  • 什麼是三級緩存
  • 三級緩存原理
  • 代碼的具體實作:有注釋
  • 工具類使用方法
  • github分享位址

1、為什麼使用三級緩存

  • 如今的 Android App 經常會需要網絡互動,通過網絡擷取圖檔是再正常不過的事了
  • 假如每次啟動的時候都從網絡拉取圖檔的話,勢必會消耗很多流量。在目前的狀況下,對于非wifi使用者來說,流量還是很貴的,一個很耗流量的應用,其使用者數量級肯定要受到影響
  • 特别是,當我們想要重複浏覽一些圖檔時,如果每一次浏覽都需要通過網絡擷取,流量的浪費可想而知
  • 是以提出三級緩存政策,通過網絡、本地、記憶體三級緩存圖檔,來減少不必要的網絡互動,避免浪費流量

2、什麼是三級緩存

  • 網絡緩存, 不優先加載, 速度慢,浪費流量
  • 本地緩存, 次優先加載, 速度快
  • 記憶體緩存, 優先加載, 速度最快

3、三級緩存原理

  • 首次加載 Android App 時,肯定要通過網絡互動來擷取圖檔,之後我們可以将圖檔儲存至本地SD卡和記憶體中
  • 之後運作 App 時,優先通路記憶體中的圖檔緩存,若記憶體中沒有,則加載本地SD卡中的圖檔
  • 總之,隻在初次通路新内容時,才通過網絡擷取圖檔資源

4、代碼的具體實作:有注釋

  • 圖檔緩存工具類
/**
 * 圖檔加載工具類(三級緩存)
 * <p>
 * 注意:
 * 1.首次加載 Android App 時,肯定要通過網絡互動來擷取圖檔,之後我們可以将圖檔儲存至本地SD卡和記憶體中
 * 2.之後運作 App 時,優先通路記憶體中的圖檔緩存,若記憶體中沒有,則加載本地SD卡中的圖檔
 * 3.總之,隻在初次通路新内容時,才通過網絡擷取圖檔資源
 * Created by zxp on 2016/6/17.
 */
public class ImageLoaderUtils {

    private static volatile ImageLoaderUtils imageLoaderUtils;

    private MenoryCacheUtils menoryCacheUtils;//記憶體緩存
    private LocalCacheUtils localCacheUtils;//本地緩存
    private NetBitmapUtils netBitmapUtils;//網絡加載

    //單例模式
    public static ImageLoaderUtils getInstance() {
        if (null == imageLoaderUtils) {
            synchronized (ImageLoaderUtils.class) {
                if (null == imageLoaderUtils) {
                    imageLoaderUtils = new ImageLoaderUtils();
                }
            }
        }
        return imageLoaderUtils;
    }

    /**
     * 加載圖檔
     *
     * @param imageView 圖檔視圖
     * @param url       圖檔位址
     */
    public void setImageViewFromBitmap(ImageView imageView, String url) {
        setImageViewFromBitmap(imageView, url, NetBitmapUtils.BITMAP_INSAMPLESIZE_ONE);
    }

    /**
     * 加載圖檔
     *
     * @param imageView      圖檔視圖
     * @param url            圖檔位址
     * @param compressNumber 壓縮倍率
     */
    public void setImageViewFromBitmap(ImageView imageView, String url, int compressNumber) {
        if (menoryCacheUtils == null) {
            menoryCacheUtils = new MenoryCacheUtils();
        }
        if (localCacheUtils == null) {
            localCacheUtils = new LocalCacheUtils();
        }
        if (netBitmapUtils == null) {
            netBitmapUtils = new NetBitmapUtils(menoryCacheUtils, localCacheUtils);
        }
        Bitmap bitmap;
        //從記憶體緩存
        bitmap = menoryCacheUtils.getBitmap(url);
        if (bitmap != null) {
            setImageView(imageView, bitmap);
            return;
        }
        //本地緩存
        bitmap = localCacheUtils.getBitmap(url);
        if (bitmap != null) {
            setImageView(imageView, bitmap);
            menoryCacheUtils.saveBitmap(url, bitmap);
            return;
        }
        //網絡擷取
        netBitmapUtils.getBitmap(imageView, url, compressNumber);
    }

    //設定圖檔
    private void setImageView(ImageView imageView, Bitmap bitmap) {
        imageView.setImageBitmap(bitmap);
    }
}
           
  • 記憶體緩存工具類
/**
 * 記憶體緩存
 * Created by zxp on 2016/6/17.
 */
public class MenoryCacheUtils {

    private LruCache<String, Bitmap> lruCache;

    public MenoryCacheUtils() {
        //通常得到手機最大記憶體的1/8,如果app在使用過程中超過這個,會自動回收
        long maxMenory = Runtime.getRuntime().maxMemory() / ;
        lruCache = new LruCache<String, Bitmap>((int) maxMenory) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getByteCount();
            }
        };
    }

    /**
     * 寫入圖檔到記憶體
     *
     * @param url    位址
     * @param bitmap 圖檔
     */
    public void saveBitmap(String url, Bitmap bitmap) {
        lruCache.put(url, bitmap);
    }

    /**
     * 從記憶體中拿到圖檔
     *
     * @param url 位址
     */
    public Bitmap getBitmap(String url) {
        return lruCache.get(url);
    }

}
           
  • 本地緩存工具類
/**
 * 本地緩存工具類
 * Created by zxp on 2016/6/17.
 */
public class LocalCacheUtils {

    //檔案村粗的路徑
    private static final String CACHE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() +
            "/ImageCache";

    /**
     * 拿到本地存儲的圖檔
     *
     * @param url 位址
     * @return
     */
    public Bitmap getBitmap(String url) {
        try {
            //截取檔案名字
            String fileName = url.substring(url.lastIndexOf("/") + , url.lastIndexOf("."));
            File file = new File(CACHE_PATH, fileName);

            Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
            return bitmap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 儲存圖檔到本地
     *
     * @param url    位址
     * @param bitmap 圖檔
     */
    public void saveBitmap(String url, Bitmap bitmap) {
        try {
            String fileName = url.substring(url.lastIndexOf("/") + , url.lastIndexOf("."));
            File file = new File(CACHE_PATH, fileName);

            //判斷父目錄是否存在,不存在建立一個
            File parentFile = file.getParentFile();
            if (!parentFile.exists()) {
                parentFile.mkdirs();
            }

            //儲存圖檔到本地,
            // 注意第二個參數:如果不壓縮是100,表示壓縮率為0,如果是30,表示壓縮70%;
            bitmap.compress(Bitmap.CompressFormat.JPEG, , new FileOutputStream(file));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
           
  • 網路加載工具類
**
 * 網絡加載圖檔工具類
 * 網絡請求拿到的結果資料bitmap,再儲存在本地和記憶體中
 * Created by zxp on //
 */
public class NetBitmapUtils {

    public static final int BITMAP_INSAMPLESIZE_ONE = ;//原圖
    public static final int BITMAP_INSAMPLESIZE_HALF = ;//寬高變為1/2
    public static final int BITMAP_INSAMPLESIZE_ONE_THIRD = ;//寬高變為1/3
    public static final int BITMAP_INSAMPLESIZE_ONE_QUARTER = ;//寬高變為1/4

    private LocalCacheUtils localCacheUtils;
    private MenoryCacheUtils menoryCacheUtils;

    //圖檔壓縮倍率(比如:1為不壓縮,2為壓縮寬高為一半)
    private int compressNumber = ;

    public NetBitmapUtils(MenoryCacheUtils menoryCacheUtils, LocalCacheUtils localCacheUtils) {
        this.menoryCacheUtils = menoryCacheUtils;
        this.localCacheUtils = localCacheUtils;
    }

    public NetBitmapUtils(MenoryCacheUtils menoryCacheUtils, LocalCacheUtils localCacheUtils, int compressNumber) {
        this.menoryCacheUtils = menoryCacheUtils;
        this.localCacheUtils = localCacheUtils;
        this.compressNumber = compressNumber;
    }

    /**
     * 網絡下載下傳圖檔
     *
     * @param iv  顯示圖檔的imagview
     * @param url 網絡下載下傳的位址
     */
    public void getBitmap(ImageView iv, String url) {
        getBitmap(iv, url, compressNumber);
    }

    /**
     * 網絡下載下傳圖檔
     *
     * @param iv             顯示圖檔的imagview
     * @param url            網絡下載下傳的位址
     * @param compressnumber 圖檔壓縮倍率(1為不壓縮)
     */
    public void getBitmap(ImageView iv, String url, int compressnumber) {
        this.compressNumber = compressnumber;
        new ImageViewTask().execute(iv, url, compressnumber);
    }

    /**
     * AsyncTask就是對handler和線程池的封裝
     * 第一個泛型:參數類型
     * 第二個泛型:更新進度的泛型
     * 第三個泛型:onPostExecute的傳回結果
     */
    class ImageViewTask extends AsyncTask<Object, Void, Bitmap> {

        private ImageView iv;
        private String url;
        private int compressNumber;


        //在背景做耗時操作,運作在子線程
        @Override
        protected Bitmap doInBackground(Object... params) {
            iv = (ImageView) params[];
            url = (String) params[];
            compressNumber = (int) params[];
            return downloadBitmap(url);
        }

        //更新進步,在主線程
        @Override
        protected void onProgressUpdate(Void... values) {
            super.onProgressUpdate(values);
        }

        //耗時方法(請求網絡)結束後執行該方法,在主線程中,帶有請求結果的傳回值
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            if (bitmap != null) {
                iv.setImageBitmap(bitmap);
                //網絡拿到的圖檔儲存到本地
                localCacheUtils.saveBitmap(url, bitmap);
                //網絡拿到的圖檔儲存到記憶體中
                menoryCacheUtils.saveBitmap(url, bitmap);
            }
        }

        private Bitmap downloadBitmap(String url) {

            HttpURLConnection connection = null;
            try {
                connection = (HttpURLConnection) new URL(url).openConnection();
                connection.setConnectTimeout();
                connection.setReadTimeout();
                connection.setRequestMethod("GET");

                //請求成功
                if (connection.getResponseCode() == ) {
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    //圖檔壓縮
                    if (compressNumber > ) {
                        //如果compressNumber為2,寬高壓縮為原來的1/2
                        options.inSampleSize = compressNumber;
                    }
                    //ALPHA_8——代表8位Alpha位圖
                    //ARGB_4444——代表16位ARGB位圖
                    //ARGB_8888——代表32位ARGB位圖
                    //RGB_565——代表8位RGB位圖
                    options.inPreferredConfig = Bitmap.Config.ARGB_4444;
                    Bitmap bitmap = BitmapFactory.decodeStream(connection.getInputStream(), null, options);
                    return bitmap;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

    }
}
           

工具類使用方法

ImageLoaderUtils.getInstance().setImageViewFromBitmap(imageView , url);

圖檔寬高壓縮為原來一半:

ImageLoaderUtils.getInstance().setImageViewFromBitmap(imageView , url , 2);

github分享位址

github的Demo