国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android圖片緩存之Lru算法(二)

2019-12-12 05:50:02
字體:
來源:轉載
供稿:網友

前言:
上篇我們總結了Bitmap的處理,同時對比了各種處理的效率以及對內存占用大小,點擊查看。我們得知一個應用如果使用大量圖片就會導致OOM(out of memory),那該如何處理才能近可能的降低oom發生的概率呢?之前我們一直在使用SoftReference軟引用,SoftReference是一種現在已經不再推薦使用的方式,因為從 Android 2.3 (API Level 9)開始,垃圾回收器會更傾向于回收持有軟引用或弱引用的對象,這讓軟引用變得不再可靠,所以今天我們來認識一種新的緩存處理算法Lru,然后學習一下基于Lru的Lrucache、DiskLruCache 實現我們的圖片緩存。 

Lru:
LRU是Least Recently Used 的縮寫,翻譯過來就是“最近最少使用”,LRU緩存就是使用這種原理實現,簡單的說就是緩存一定量的數據,當超過設定的閾值時就把一些過期的數據刪除掉,比如我們緩存10000條數據,當數據小于10000時可以隨意添加,當超過10000時就需要把新的數據添加進來,同時要把過期數據刪除,以確保我們最大緩存10000條,那怎么確定刪除哪條過期數據呢,采用LRU算法實現的話就是將最老的數據刪掉。

基于LruCache實現內存緩存:
1.)初始化MemoryCache
這里內存緩存的是Drawable 而不是Bitmap 理由是Drawable相對Bitmap來說有很大的內存優勢        

 int maxMemory = (int) Runtime.getRuntime().maxMemory();//獲取系統分配給應用的總內存大小 int mCacheSize = maxMemory / 8;//設置圖片內存緩存占用八分之一 mMemoryCache = new LruCache<String, Drawable>(mCacheSize) {  //必須重寫此方法,來測量Bitmap的大小  @Override  protected int sizeOf(String key, Drawable value) {  if (value instanceof BitmapDrawable) {   Bitmap bitmap = ((BitmapDrawable) value).getBitmap();   return bitmap == null ? 0 : bitmap.getByteCount();  }  return super.sizeOf(key, value);  } };

2.)添加一個Drawable到內存緩存 

 /** * 添加Drawable到內存緩存 * * @param key * @param drawable */ private void addDrawableToMemoryCache(String key, Drawable drawable) { if (getDrawableFromMemCache(key) == null && drawable != null) {  mMemoryCache.put(key, drawable); } }

3.)從內存緩存中獲取一個Drawable

 /** * 從內存緩存中獲取一個Drawable * * @param key * @return */ public Drawable getDrawableFromMemCache(String key) { return mMemoryCache.get(key); }

4.)從內存緩存中移除一個Drawable

 /** * 從內存緩存中移除 * * @param key */ public void removeCacheFromMemory(String key) { mMemoryCache.remove(key); }

5.)清空內存緩存

 /** * 清理內存緩存 */ public void cleanMemoryCCache() { mMemoryCache.evictAll(); } 

其實Lru緩存機制本質上就是存儲在一個LinkedHashMap存儲,為了保障插入的數據順序,方便清理。 

基于DiskLruCache實現磁盤緩存:
DiskLruCache類并不是谷歌官方實現,需要自行下載,下載地址:https://github.com/JakeWharton/DiskLruCache

1.)初始化DiskLruCache 

 File cacheDir = context.getCacheDir();//指定的是數據的緩存地址 long diskCacheSize = 1024 * 1024 * 30;//最多可以緩存多少字節的數據 int appVersion = DiskLruUtils.getAppVersion(context);//指定當前應用程序的版本號 int valueCount = 1;//指定同一個key可以對應多少個緩存文件 try {  mDiskCache = DiskLruCache.open(cacheDir, appVersion, valueCount, diskCacheSize); } catch (Exception ex) { }

2.)寫入一個文件到磁盤緩存 

 /** * 添加Bitmap到磁盤緩存 * * @param key * @param value */ private void addBitmapToDiskCache(String key, byte[] value) { OutputStream out = null; try {  DiskLruCache.Editor editor = mDiskCache.edit(key);  if (editor != null) {  out = editor.newOutputStream(0);  if (value != null && value.length > 0) {   out.write(value);   out.flush();   editor.commit();  } else {   editor.abort();  }  }  mDiskCache.flush(); } catch (IOException e) {  e.printStackTrace(); } finally {  DiskLruUtils.closeQuietly(out); } }

3.)從磁盤緩存中讀取Drawable 

 /** * 從磁盤緩存中獲取一個Drawable * * @param key * @return */ public Drawable getDrawableFromDiskCache(String key) { try {  DiskLruCache.Snapshot snapShot = mDiskCache.get(key);  if (snapShot != null) {  InputStream is = snapShot.getInputStream(0);  Bitmap bitmap = BitmapFactory.decodeStream(is);  Drawable drawable = DiskLruUtils.bitmap2Drawable(bitmap);  //從磁盤中讀取到之后 加入內存緩存  addDrawableToMemoryCache(key, drawable);  return drawable;  } } catch (IOException e) {  e.printStackTrace(); } return null; }

4.)從磁盤緩存中移除

 /** * 從磁盤緩存中移除 * * @param key */ public void removeCacheFromDisk(String key) { try {  mDiskCache.remove(key); } catch (Exception e) { } }

5.)清空磁盤緩存 

 /** * 清理磁盤緩存 */ public void cleanDiskCache() { try {  mDiskCache.delete(); } catch (Exception e) { } }

圖片下載過程:
接下來實例中用到了一點RxJava的知識有不了解RxJava的請自行了解一下。 
1.)采用異步方式操作磁盤緩存和網絡下載, 內存緩存可以在主線程中操作 

 public void disPlay(final ImageView imageView, String imageUrl) {  //生成唯一key  final String key = DiskLruUtils.hashKeyForDisk(imageUrl);  //先從內存中讀取  Drawable drawableFromMemCache = getDrawableFromMemCache(key);  if (drawableFromMemCache != null) {   imageView.setImageDrawable(drawableFromMemCache);   return;  }  Observable.just(imageUrl)    .map(new Func1<String, Drawable>() {     @Override     public Drawable call(String imageUrl) { // 參數類型 String      //從磁盤中讀取      Drawable drawableFromDiskCache = getDrawableFromDiskCache(key);      if (drawableFromDiskCache != null) {       return drawableFromDiskCache;      }      //網絡下載      return download(imageUrl); // 返回類型 Drawable     }    })    .subscribeOn(Schedulers.io()) // 指定 subscribe() 發生在 IO 線程    .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調發生在主線程    .subscribe(new Action1<Drawable>() {     @Override     public void call(Drawable drawable) { // 參數類型 Drawable      imageView.setImageDrawable(drawable);     }    }); }

2.)下載圖片過程以及處理 

 private Drawable download(String imageUrl) {  HttpURLConnection urlConnection = null;  ByteArrayOutputStream bos = null;  InputStream ins = null;  try {   final URL url = new URL(imageUrl);   urlConnection = (HttpURLConnection) url.openConnection();   ins = urlConnection.getInputStream();   bos = new ByteArrayOutputStream();   int b;   while ((b = ins.read()) != -1) {    bos.write(b);   }   bos.flush();   byte[] bytes = bos.toByteArray();   Bitmap bitmap = DiskLruUtils.bytes2Bitmap(bytes);   String key = DiskLruUtils.hashKeyForDisk(imageUrl);   Drawable drawable = DiskLruUtils.bitmap2Drawable(bitmap);   //加入內存緩存   addDrawableToMemoryCache(key, drawable);   //加入磁盤緩存   addBitmapToDiskCache(key, bytes);   return drawable;  } catch (IOException e) {   e.printStackTrace();  } finally {   if (urlConnection != null) {    urlConnection.disconnect();   }   DiskLruUtils.closeQuietly(bos);   DiskLruUtils.closeQuietly(ins);  }  return null; }

附上最終圖片緩存單例簡單實現全部代碼以及DiskLruUtils工具類代碼
 ImageLoadManager.java

public class ImageLoadManager { private LruCache<String, Drawable> mMemoryCache;//內存緩存 private DiskLruCache mDiskCache;//磁盤緩存 private static ImageLoadManager mInstance;//獲取圖片下載單例引用 /**  * 構造器  *  * @param context  */ private ImageLoadManager(Context context) {  int maxMemory = (int) Runtime.getRuntime().maxMemory();//獲取系統分配給應用的總內存大小  int mCacheSize = maxMemory / 8;//設置圖片內存緩存占用八分之一  mMemoryCache = new LruCache<String, Drawable>(mCacheSize) {   //必須重寫此方法,來測量Bitmap的大小   @Override   protected int sizeOf(String key, Drawable value) {    if (value instanceof BitmapDrawable) {     Bitmap bitmap = ((BitmapDrawable) value).getBitmap();     return bitmap == null ? 0 : bitmap.getByteCount();    }    return super.sizeOf(key, value);   }  };  File cacheDir = context.getCacheDir();//指定的是數據的緩存地址  long diskCacheSize = 1024 * 1024 * 30;//最多可以緩存多少字節的數據  int appVersion = DiskLruUtils.getAppVersion(context);//指定當前應用程序的版本號  int valueCount = 1;//指定同一個key可以對應多少個緩存文件  try {   mDiskCache = DiskLruCache.open(cacheDir, appVersion, valueCount, diskCacheSize);  } catch (Exception ex) {  } } /**  * 獲取單例引用  *  * @return  */ public static ImageLoadManager getInstance(Context context) {  ImageLoadManager inst = mInstance;  if (inst == null) {   synchronized (RequestManager.class) {    inst = mInstance;    if (inst == null) {     inst = new ImageLoadManager(context.getApplicationContext());     mInstance = inst;    }   }  }  return inst; } public void disPlay(final ImageView imageView, String imageUrl) {  //生成唯一key  final String key = DiskLruUtils.hashKeyForDisk(imageUrl);  //先從內存中讀取  Drawable drawableFromMemCache = getDrawableFromMemCache(key);  if (drawableFromMemCache != null) {   imageView.setImageDrawable(drawableFromMemCache);   return;  }  Observable.just(imageUrl)    .map(new Func1<String, Drawable>() {     @Override     public Drawable call(String imageUrl) { // 參數類型 String      //從磁盤中讀取      Drawable drawableFromDiskCache = getDrawableFromDiskCache(key);      if (drawableFromDiskCache != null) {       return drawableFromDiskCache;      }      //網絡下載      return download(imageUrl); // 返回類型 Drawable     }    })    .subscribeOn(Schedulers.io()) // 指定 subscribe() 發生在 IO 線程    .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調發生在主線程    .subscribe(new Action1<Drawable>() {     @Override     public void call(Drawable drawable) { // 參數類型 Drawable      imageView.setImageDrawable(drawable);     }    }); } /**  * 添加Drawable到內存緩存  *  * @param key  * @param drawable  */ private void addDrawableToMemoryCache(String key, Drawable drawable) {  if (getDrawableFromMemCache(key) == null && drawable != null) {   mMemoryCache.put(key, drawable);  } } /**  * 從內存緩存中獲取一個Drawable  *  * @param key  * @return  */ public Drawable getDrawableFromMemCache(String key) {  return mMemoryCache.get(key); } /**  * 從磁盤緩存中獲取一個Drawable  *  * @param key  * @return  */ public Drawable getDrawableFromDiskCache(String key) {  try {   DiskLruCache.Snapshot snapShot = mDiskCache.get(key);   if (snapShot != null) {    InputStream is = snapShot.getInputStream(0);    Bitmap bitmap = BitmapFactory.decodeStream(is);    Drawable drawable = DiskLruUtils.bitmap2Drawable(bitmap);    //從磁盤中讀取到之后 加入內存緩存    addDrawableToMemoryCache(key, drawable);    return drawable;   }  } catch (IOException e) {   e.printStackTrace();  }  return null; } /**  * 添加Bitmap到磁盤緩存  *  * @param key  * @param value  */ private void addBitmapToDiskCache(String key, byte[] value) {  OutputStream out = null;  try {   DiskLruCache.Editor editor = mDiskCache.edit(key);   if (editor != null) {    out = editor.newOutputStream(0);    if (value != null && value.length > 0) {     out.write(value);     out.flush();     editor.commit();    } else {     editor.abort();    }   }   mDiskCache.flush();  } catch (IOException e) {   e.printStackTrace();  } finally {   DiskLruUtils.closeQuietly(out);  } } private Drawable download(String imageUrl) {  HttpURLConnection urlConnection = null;  ByteArrayOutputStream bos = null;  InputStream ins = null;  try {   final URL url = new URL(imageUrl);   urlConnection = (HttpURLConnection) url.openConnection();   ins = urlConnection.getInputStream();   bos = new ByteArrayOutputStream();   int b;   while ((b = ins.read()) != -1) {    bos.write(b);   }   bos.flush();   byte[] bytes = bos.toByteArray();   Bitmap bitmap = DiskLruUtils.bytes2Bitmap(bytes);   String key = DiskLruUtils.hashKeyForDisk(imageUrl);   Drawable drawable = DiskLruUtils.bitmap2Drawable(bitmap);   //加入內存緩存   // addDrawableToMemoryCache(key, drawable);   //加入磁盤緩存   addBitmapToDiskCache(key, bytes);   return drawable;  } catch (IOException e) {   e.printStackTrace();  } finally {   if (urlConnection != null) {    urlConnection.disconnect();   }   DiskLruUtils.closeQuietly(bos);   DiskLruUtils.closeQuietly(ins);  }  return null; } /**  * 從緩存中移除  *  * @param key  */ public void removeCache(String key) {  removeCacheFromMemory(key);  removeCacheFromDisk(key); } /**  * 從內存緩存中移除  *  * @param key  */ public void removeCacheFromMemory(String key) {  mMemoryCache.remove(key); } /**  * 從磁盤緩存中移除  *  * @param key  */ public void removeCacheFromDisk(String key) {  try {   mDiskCache.remove(key);  } catch (Exception e) {  } } /**  * 磁盤緩存大小  *  * @return  */ public long diskCacheSize() {  return mDiskCache.size(); } /**  * 內存緩存大小  *  * @return  */ public long memoryCacheSize() {  return mMemoryCache.size(); } /**  * 關閉磁盤緩存  */ public void closeDiskCache() {  try {   mDiskCache.close();  } catch (Exception e) {  } } /**  * 清理緩存  */ public void cleanCache() {  cleanMemoryCCache();  cleanDiskCache(); } /**  * 清理磁盤緩存  */ public void cleanDiskCache() {  try {   mDiskCache.delete();  } catch (Exception e) {  } } /**  * 清理內存緩存  */ public void cleanMemoryCCache() {  mMemoryCache.evictAll(); }}

DiskLruUtils.java

final class DiskLruUtils { /**  * 關閉輸入輸出流  */ public static void closeQuietly(/*Auto*/Closeable closeable) {  if (closeable != null) {   try {    closeable.close();   } catch (RuntimeException rethrown) {    throw rethrown;   } catch (Exception ignored) {   }  } } /**  * 獲取versionCode  */ public static int getAppVersion(Context context) {  try {   PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);   return info.versionCode;  } catch (PackageManager.NameNotFoundException e) {   e.printStackTrace();  }  return 1; } public static String hashKeyForDisk(String key) {  String cacheKey;  try {   final MessageDigest mDigest = MessageDigest.getInstance("MD5");   mDigest.update(key.getBytes());   cacheKey = bytesToHexString(mDigest.digest());  } catch (NoSuchAlgorithmException e) {   cacheKey = String.valueOf(key.hashCode());  }  return cacheKey; } public static String bytesToHexString(byte[] bytes) {  StringBuilder sb = new StringBuilder();  for (int i = 0; i < bytes.length; i++) {   String hex = Integer.toHexString(0xFF & bytes[i]);   if (hex.length() == 1) {    sb.append('0');   }   sb.append(hex);  }  return sb.toString(); } /**  * Bitmap → bytes  */ public static byte[] bitmap2Bytes(Bitmap bm) {  if (bm == null) {   return null;  }  ByteArrayOutputStream baos = new ByteArrayOutputStream();  bm.compress(Bitmap.CompressFormat.PNG, 100, baos);  return baos.toByteArray(); } /**  * bytes → Bitmap  */ public static Bitmap bytes2Bitmap(byte[] bytes) {  return BitmapFactory.decodeByteArray(bytes, 0, bytes.length); } /**  * Drawable → Bitmap  */ public static Bitmap drawable2Bitmap(Drawable drawable) {  if (drawable == null) {   return null;  }  // 取 drawable 的長寬  int w = drawable.getIntrinsicWidth();  int h = drawable.getIntrinsicHeight();  // 取 drawable 的顏色格式  Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;  // 建立對應 bitmap  Bitmap bitmap = Bitmap.createBitmap(w, h, config);  // 建立對應 bitmap 的畫布  Canvas canvas = new Canvas(bitmap);  drawable.setBounds(0, 0, w, h);  // 把 drawable 內容畫到畫布中  drawable.draw(canvas);  return bitmap; } /*   * Bitmap → Drawable   */ public static Drawable bitmap2Drawable(Bitmap bm) {  if (bm == null) {   return null;  }  BitmapDrawable bd = new BitmapDrawable(bm);  bd.setTargetDensity(bm.getDensity());  return new BitmapDrawable(bm); }}

 以上就是基于Lru圖片緩存簡單實現,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 伊宁县| 马鞍山市| 余干县| 丹东市| 常山县| 平顺县| 威远县| 汨罗市| 黄陵县| 达拉特旗| 临清市| 天祝| 延长县| 南雄市| 本溪| 屏山县| 滕州市| 土默特右旗| 长顺县| 大足县| 永嘉县| 米脂县| 禹州市| 泾源县| 饶河县| 漯河市| 昌都县| 琼中| 长治县| 常熟市| 晋江市| 诏安县| 乌恰县| 湖口县| 阳春市| 娄烦县| 玛多县| 余姚市| 牡丹江市| 青州市| 扎赉特旗|