Lru:
LRU是Least Recently Used 的縮寫,翻譯過來就是“最近最少使用”,LRU緩存就是使用這種原理實(shí)現(xiàn),簡單的說就是緩存一定量的數(shù)據(jù),當(dāng)超過設(shè)定的閾值時(shí)就把一些過期的數(shù)據(jù)刪除掉,比如我們緩存10000條數(shù)據(jù),當(dāng)數(shù)據(jù)小于10000時(shí)可以隨意添加,當(dāng)超過10000時(shí)就需要把新的數(shù)據(jù)添加進(jìn)來,同時(shí)要把過期數(shù)據(jù)刪除,以確保我們最大緩存10000條,那怎么確定刪除哪條過期數(shù)據(jù)呢,采用LRU算法實(shí)現(xiàn)的話就是將最老的數(shù)據(jù)刪掉。
基于LruCache實(shí)現(xiàn)內(nèi)存緩存:
1.)初始化MemoryCache
這里內(nèi)存緩存的是Drawable 而不是Bitmap 理由是Drawable相對Bitmap來說有很大的內(nèi)存優(yōu)勢

intmaxMemory = (int) Runtime.getRuntime().maxMemory();//獲取系統(tǒng)分配給應(yīng)用的總內(nèi)存大小intmCacheSize = maxMemory / 8;//設(shè)置圖片內(nèi)存緩存占用八分之一mMemoryCache =newLruCache(mCacheSize) {//必須重寫此方法,來測量Bitmap的大小@OverrideprotectedintsizeOf(String key, Drawable value) {if(valueinstanceofBitmapDrawable) {
Bitmap bitmap=((BitmapDrawable) value).getBitmap();returnbitmap ==null? 0: bitmap.getByteCount();
}returnsuper.sizeOf(key, value);
}
};

2.)添加一個(gè)Drawable到內(nèi)存緩存

/*** 添加Drawable到內(nèi)存緩存
*
*@paramkey
*@paramdrawable*/privatevoidaddDrawableToMemoryCache(String key, Drawable drawable) {if(getDrawableFromMemCache(key) ==null&& drawable !=null) {
mMemoryCache.put(key, drawable);
}
}

3.)從內(nèi)存緩存中獲取一個(gè)Drawable

/*** 從內(nèi)存緩存中獲取一個(gè)Drawable
*
*@paramkey
*@return*/publicDrawable getDrawableFromMemCache(String key) {returnmMemoryCache.get(key);
}

4.)從內(nèi)存緩存中移除一個(gè)Drawable

/*** 從內(nèi)存緩存中移除
*
*@paramkey*/publicvoidremoveCacheFromMemory(String key) {
mMemoryCache.remove(key);
}

5.)清空內(nèi)存緩存
/*** 清理內(nèi)存緩存*/publicvoidcleanMemoryCCache() {
mMemoryCache.evictAll();
}
其實(shí)Lru緩存機(jī)制本質(zhì)上就是存儲(chǔ)在一個(gè)LinkedHashMap存儲(chǔ),為了保障插入的數(shù)據(jù)順序,方便清理。
基于DiskLruCache實(shí)現(xiàn)磁盤緩存:
DiskLruCache類并不是谷歌官方實(shí)現(xiàn),需要自行下載,下載地址:https://github.com/JakeWharton/DiskLruCache
1.)初始化DiskLruCache

File cacheDir = context.getCacheDir();//指定的是數(shù)據(jù)的緩存地址longdiskCacheSize = 1024 * 1024 * 30;//最多可以緩存多少字節(jié)的數(shù)據(jù)intappVersion = DiskLruUtils.getAppVersion(context);//指定當(dāng)前應(yīng)用程序的版本號intvalueCount = 1;//指定同一個(gè)key可以對應(yīng)多少個(gè)緩存文件try{
mDiskCache=DiskLruCache.open(cacheDir, appVersion, valueCount, diskCacheSize);
}catch(Exception ex) {
}

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

/*** 添加Bitmap到磁盤緩存
*
*@paramkey
*@paramvalue*/privatevoidaddBitmapToDiskCache(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

/*** 從磁盤緩存中獲取一個(gè)Drawable
*
*@paramkey
*@return*/publicDrawable 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);//從磁盤中讀取到之后 加入內(nèi)存緩存addDrawableToMemoryCache(key, drawable);returndrawable;
}
}catch(IOException e) {
e.printStackTrace();
}returnnull;
}

4.)從磁盤緩存中移除

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

5.)清空磁盤緩存

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

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

publicvoiddisPlay(finalImageView imageView, String imageUrl) {//生成唯一keyfinalString key =DiskLruUtils.hashKeyForDisk(imageUrl);//先從內(nèi)存中讀取Drawable drawableFromMemCache =getDrawableFromMemCache(key);if(drawableFromMemCache !=null) {
imageView.setImageDrawable(drawableFromMemCache);return;
}
Observable.just(imageUrl)
.map(newFunc1() {
@OverridepublicDrawable call(String imageUrl) {//參數(shù)類型 String//從磁盤中讀取Drawable drawableFromDiskCache =getDrawableFromDiskCache(key);if(drawableFromDiskCache !=null) {returndrawableFromDiskCache;
}//網(wǎng)絡(luò)下載returndownload(imageUrl);//返回類型 Drawable}
})
.subscribeOn(Schedulers.io())//指定 subscribe() 發(fā)生在 IO 線程.observeOn(AndroidSchedulers.mainThread())//指定 Subscriber 的回調(diào)發(fā)生在主線程.subscribe(newAction1() {
@Overridepublicvoidcall(Drawable drawable) {//參數(shù)類型 DrawableimageView.setImageDrawable(drawable);
}
});
}

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

privateDrawable download(String imageUrl) {
HttpURLConnection urlConnection=null;
ByteArrayOutputStream bos=null;
InputStream ins=null;try{finalURL url =newURL(imageUrl);
urlConnection=(HttpURLConnection) url.openConnection();
ins=urlConnection.getInputStream();
bos=newByteArrayOutputStream();intb;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);//加入內(nèi)存緩存addDrawableToMemoryCache(key, drawable);//加入磁盤緩存addBitmapToDiskCache(key, bytes);returndrawable;
}catch(IOException e) {
e.printStackTrace();
}finally{if(urlConnection !=null) {
urlConnection.disconnect();
}
DiskLruUtils.closeQuietly(bos);
DiskLruUtils.closeQuietly(ins);
}returnnull;
}

附上最終圖片緩存單例簡單實(shí)現(xiàn)全部代碼以及DiskLruUtils工具類代碼
ImageLoadManager.java
ImageLoadManager.java

DiskLruUtils.java
DiskLruUtils.java

總結(jié):
以上就是基于Lru圖片緩存簡單實(shí)現(xiàn)