本文主要分析以下幾點
- 為什麼使用三級緩存
- 什麼是三級緩存
- 三級緩存原理
- 代碼的具體實作:有注釋
- 工具類使用方法
- 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