標籤:des android style blog http color 使用 os
圖片緩衝策略
1、圖片緩衝策略分析
從網路上載入一張圖,然後把它顯示到UI上是個很簡單的事情。當圖片變多時,處理起來就有些麻煩了,很典型的應用情境,如ListView,GridView或者ViePager等。我們既需要保證使用者看到更多的圖片,以免螢幕出現大面積的空白,又要保證記憶體能Hold住。
GC會自動釋放一個沒有強引用的圖片或者View,這本來是個好事情,但為了讓使用者來復原動時還能快速載入老圖片,通常會使用圖片緩衝。
下面分別討論下,通過使用Memory Cache和Disk Cache來增加UI的響應速度和流暢度。
一、使用Memory Cache
Memory Cache花費定量的記憶體來換取對圖片的快速存取。可以使用LruCache來快速實現。過去,我們通常使用SoftReference或WeakReference來實現Memory Cache,但是在Android 2.3 (API Level 9)之後,GC對SoftReference和WeakReference回收的更快,所以,SoftReference和WeakReference的效果就很差了。而且,在Android 3.0 (API Level 11)之前,Bitmap的像素資料存放在Native Memory中,如何釋放是不確定的,存在著記憶體流失,甚至Crash的風險。
為了確定LruCache的大小,我們需要參考如下幾個因素:
1、當前進程的剩餘記憶體有多少
2、為了保證良好的使用者體驗,應用情境顯示多少張圖片可以滿足要求?
3、螢幕的density是多少?不同像素的螢幕對圖片品質的要求是不一樣的,可以據此在取圖時做一些最佳化。
4、圖片被訪問的頻率是否相差很多?如果是這樣的話可以存放在不同的LruCache中。
5、有時需要在數量和品質之間做一些平衡。比如為圖片列表在Memory Cache中緩衝
較多的縮圖,在UI中先顯示縮圖,然後在後台載入一張高清的。
這裡沒有一個精確的數字來做為指導,需要我們在實際中就以上幾個因素進行權衡,設定合適的值。至於如何使用LruCache可以參考Support Library中的Demo。
二、使用Disk Cache
Memory Cache可以加快圖片的訪問速度,但記憶體有限,不可能所有圖片都放在Memory Cache中。當程式先被擠出記憶體,後又被重新啟動時,圖片仍需要重新擷取。這個時候,可以應用Disk Cache來緩衝圖片,圖片就不需要從網路上擷取了,節省了流量,減少了擷取時間。但需要注意,Disk Cache的讀取涉及到本地IO操作,需要開啟後台線程操作。
我們可以像系統Gallery那樣使用ContentProvider。另外,Disk Cache也可以很簡單地通過Android源碼中提供的DiskLruCache來實現。
2、圖片緩衝實現
一、記憶體緩衝
//需要匯入外部jar檔案 android-support-v4.jar
importandroid.support.v4.util.LruCache;
//開闢8M硬緩衝空間
private final int hardCachedSize =8*1024*1024;
//hardcache 強引用
private final LruCache<String,Bitmap> sHardBitmapCache = new LruCache<String, Bitmap>(hardCachedSize)
{
@Override
public int sizeOf(Stringkey, Bitmap value)
{
return value.getRowBytes() *value.getHeight();
}
@Override
protected voidentryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue)
{
Log.v("tag","hard cache is full , push to soft cache");
//硬引用緩衝區滿,將一個最不經常使用的oldvalue推入到軟引用緩衝區
sSoftBitmapCahe.put(key,new SoftReference<Bitmap>(oldValue));
}
}
//軟引用
private static final intSOFT_CACHE_CAPACITY = 40;
private final static LinkedHashMap<String,SoftReference<Bitmap>> sSoftBitmapCache = new LinkedHashMao<String,SoftReference<Bitmap>>(SOFT_CACHE_CAPACITY, 0.75f, true)
{
@Override
publicSoftReference<Bitmap> put(String key, SoftReference<Bitmap> value)
{
returnsuper.input(key, value);
}
@Override
protectedboolean removeEldestEntry(LinkedHashMap.Entry<Stirng,SoftReference<Bitmap>> eldest)
{
if(size() >SOFT_CACHE_CAPACITY)
{
Log.v("tag","Soft Reference limit , purge one");
return true;
}
return false;
}
}
//緩衝bitmap
public boolean putBitmap(String key,Bitmap bitmap)
{
if(bitmap !=null)
{
synchronized(sHardBitmapCache)
{
sHardBitmapCache.put(key,bitmap);
}
return true;
}
return false;
}
//從緩衝中擷取bitmap
public Bitmap getBitmap(String key)
{
synchronized(sHardBitmapCache)
{
final Bitmapbitmap = sHardBitmapCache.get(key);
if(bitmap !=null)
{
return bitmap;
}
}
//硬引用緩衝區間中讀取失敗,從軟引用緩衝區間讀取
synchronized(sSoftBitmapCache)
{
SoftReference<Bitmap>bitmapReference = sSoftBtimapCache.get(key);
if(bitmapReference != null)
{
final Bitmapbitmap2 = bitmapReference.get();
if(bitmap2 !=null)
{
return bitmap2;
}
else
{
Log.v("tag","soft reference 已經被回收");
sSoftBitmapCache.remove(key);
}
}
}
return null;
}
二、磁碟檔案快取
private File mCacheDir = context.getCacheDir();
private static final int MAX_CACHE_SIZE = 20 * 1024 * 1024; //20M
private final LruCache<String, Long> sFileCache = new LruCache<String, Long>(MAX_CACHE_SIZE)
{
@Override
public int sizeOf(Stringkey, Long value)
{
return value.intValue();
}
@Override
protected void entryRemoved(booleanevicted, String key, Long oldValue, Long newValue)
{
File file = getFile(key);
if(file != null)
{
file.delete();
}
}
private File getFile(String fileName)throws FileNotFoundException
{
File file = new File(mCacheDir, fileName);
if(!file.exists() || !file.isFile())
{
thrownew FileNotFoundException("檔案不存在或有同名檔案夾");
}
return file;
}
//緩衝bitmap到外部儲存
public boolean putBitmap(String key, Bitmapbitmap)
{
File file = getFile(key);
if(file != null)
{
Log.v("tag", "檔案已經存在");
return true;
}
FileOutputStream fos =getOutputStream(key);
boolean saved = bitmap.compress(CompressFormat.JPEG,100, fos);
fos.flush();
fos.close();
if(saved)
{
synchronized(sFileCache)
{
sFileCache.put(key,getFile(key).length());
}
return true;
}
return false;
}
//根據key擷取OutputStream
private FileOutputStreamgetOutputStream(String key)
{
if(mCacheDir == null)
return null;
FileOutputStream fos = newFileOutputStream(mCacheDir.getAbsolutePath() + File.separator + key);
return fos;
}
//擷取bitmap
private static BitmapFactory.OptionssBitmapOptions;
static
{
sBitmapOptions = newBitmapFactory.Options();
sBitmapOptions.inPurgeable=true; //bitmapcan be purged to disk
}
public Bitmap getBitmap(String key)
{
File bitmapFile = getFile(key);
if(bitmapFile != null)
{
Bitmap bitmap =BitmapFactory.decodeStream(new FileInputStream(bitmapFile), null,sBitmapOptions);
if(bitmap!= null)
{
//重新將其緩衝至硬引用中
...
}
}
}
}
摘自: android讀取大圖片並緩衝
http://www.cnblogs.com/leehongee/p/3323837.html 圖片緩衝實現策略分析 http://blog.csdn.net/a345017062/article/details/8753649