/**
* 管理內存中的圖片
*/
public class ImageCache {
private static ImageCache instance;
private Context context;
private LruCache<String, Bitmap> memoryCache;
private DiskLruCache diskLruCache;
BitmapFactory.Options options = new BitmapFactory.Options();
/**
* 定義一個複用沲
*/
public static Set<WeakReference<Bitmap>> reuseablePool;
public static ImageCache getInstance() {
if (null == instance) {
synchronized (ImageCache.class) {
if (null == instance) {
instance = new ImageCache();
}
}
}
return instance;
}
//引用隊列
ReferenceQueue referenceQueue;
Thread clearReferenceQueue;
boolean shutDown;
private ReferenceQueue<Bitmap> getReferenceQueue() {
if (null == referenceQueue) {
//當弱用引需要被回收的時候,會進到這個隊列中
referenceQueue = new ReferenceQueue<Bitmap>();
//單開一個線程,去掃描引用隊列中GC掃到的內容,交到native層去釋放
clearReferenceQueue = new Thread(new Runnable() {
@Override
public void run() {
while (!shutDown) {
try {
//remove是阻塞式的
Reference<Bitmap> reference = referenceQueue.remove();
Bitmap bitmap = reference.get();
if (null != bitmap && !bitmap.isRecycled()) {
bitmap.recycle();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
clearReferenceQueue.start();
}
return referenceQueue;
}
//dir是用來存放圖片文件的路徑
public void init(Context context, String dir) {
this.context = context.getApplicationContext();
//複用池
reuseablePool = Collections.synchronizedSet(new HashSet<WeakReference<Bitmap>>());
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
//獲取程序最大可用內存 單位是M
int memoryClass = am.getMemoryClass();
//參數表示能夠緩存的內存最大值 單位是byte
memoryCache = new LruCache<String, Bitmap>(memoryClass / 8 * 1024 * 1024) {
/**
* @return value佔用的內存大小
*/
@Override
protected int sizeOf(String key, Bitmap value) {
//19之前 必需同等大小,才能複用 inSampleSize=1
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
return value.getAllocationByteCount();
}
return value.getByteCount();
}
/**
* 拒接策略:當從lru緩存中移除後,可以獲取到被移除的Bitmap
* 當lru滿了,bitmap從lru中移除對象時,會回調
*/
@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
if (oldValue.isMutable()) {//如果是設置成能複用的內存塊,拉到java層來管理
//3.0以下 Bitmap native
//3.0以後---8.0之前 java
//8。0開始 native
//lru緩存中多餘圖片放到一個複用池中
reuseablePool.add(new WeakReference<Bitmap>(oldValue, referenceQueue));
} else {
//oldValue就是移出來的對象
oldValue.recycle();
}
}
};
//valueCount:表示一個key對應valueCount個文件
try {
diskLruCache = DiskLruCache.open(new File(dir), BuildConfig.VERSION_CODE, 1, 10 * 1024 * 1024);
} catch (Exception e) {
e.printStackTrace();
}
getReferenceQueue();
}
/**
* 加入內存緩存
*/
public void putBitmapToMemeory(String key, Bitmap bitmap) {
memoryCache.put(key, bitmap);
}
public Bitmap getBitmapFromMemory(String key) {
return memoryCache.get(key);
}
public void clearMemoryCache() {
memoryCache.evictAll();
}
//獲取複用池中的內容
public Bitmap getReuseable(int w, int h, int inSampleSize) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return null;
}
Bitmap reuseable = null;
Iterator<WeakReference<Bitmap>> iterator = reuseablePool.iterator();
while (iterator.hasNext()) {
Bitmap bitmap = iterator.next().get();
if (null != bitmap) {
//可以複用
if (checkInBitmap(bitmap, w, h, inSampleSize)) {
reuseable = bitmap;
iterator.remove();
break;
} else {
iterator.remove();
}
}
}
return reuseable;
}
private boolean checkInBitmap(Bitmap bitmap, int w, int h, int inSampleSize) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return bitmap.getWidth() == w && bitmap.getHeight() == h && inSampleSize == 1;
}
if (inSampleSize >= 1) {
w /= inSampleSize;
h /= inSampleSize;
}
int byteCount = w * h * getPixelsCount(bitmap.getConfig());
return byteCount <= bitmap.getAllocationByteCount();
}
private int getPixelsCount(Bitmap.Config config) {
if (config == Bitmap.Config.ARGB_8888) {
return 4;
}
return 2;
}
//磁盤緩存的處理
/**
* 加入磁盤緩存
*/
public void putBitMapToDisk(String key, Bitmap bitmap) {
DiskLruCache.Snapshot snapshot = null;
OutputStream os = null;
try {
snapshot = diskLruCache.get(key);
//如果緩存中已經有這個文件 不理他
if (null == snapshot) {
//如果沒有這個文件,就生成這個文件
DiskLruCache.Editor editor = diskLruCache.edit(key);
if (null != editor) {
os = editor.newOutputStream(0);
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, os);
editor.commit();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != snapshot) {
snapshot.close();
}
if (null != os) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 從磁盤緩存中取
*/
public Bitmap getBitmapFromDisk(String key, Bitmap reuseable) {
DiskLruCache.Snapshot snapshot = null;
Bitmap bitmap = null;
try {
snapshot = diskLruCache.get(key);
if (null == snapshot) {
return null;
}
//獲取文件輸入流,讀取bitmap
InputStream is = snapshot.getInputStream(0);
//解碼個圖片,寫入
options.inMutable = true;
options.inBitmap = reuseable;
bitmap = BitmapFactory.decodeStream(is, null, options);
if (null != bitmap) {
memoryCache.put(key, bitmap);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != snapshot) {
snapshot.close();
}
}
return bitmap;
}
}