android图片硬盘缓存,图片缓存策略

图片缓存策略

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

import

android.support.v4.util.LruCache;

//开辟8M硬缓存空间

private final int hardCachedSize =

8*1024*1024;

//hard

cache 强引用

private final LruCache

Bitmap> sHardBitmapCache = new LruCache(hardCachedSize)

{

public int sizeOf(String

key, Bitmap value)

{

return value.getRowBytes() *

value.getHeight();

}

protected void

entryRemoved(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(oldValue));

}

}

//软引用

private static final int

SOFT_CACHE_CAPACITY = 40;

private final static LinkedHashMap

SoftReference> sSoftBitmapCache = new  LinkedHashMao

SoftReference>(SOFT_CACHE_CAPACITY, 0.75f, true)

{

public

SoftReference put(String key, SoftReference value)

{

return

super.input(key, value);

}

protected

boolean removeEldestEntry(LinkedHashMap.Entry

SoftReference> 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 Bitmap

bitmap = sHardBitmapCache.get(key);

if(bitmap !=

null)

{

return bitmap;

}

}

//硬引用缓存区间中读取失败,从软引用缓存区间读取

synchronized(sSoftBitmapCache)

{

SoftReference

bitmapReference = sSoftBtimapCache.get(key);

if(bitmapReference != null)

{

final Bitmap

bitmap2 = 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 sFileCache = new LruCache(MAX_CACHE_SIZE)

{

[email protected]

public int sizeOf(String

key, Long value)

{

return value.intValue();

}

protected void entryRemoved(boolean

evicted, 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())

{

throw

new FileNotFoundException("文件不存在或有同名文件夹");

}

return file;

}

//缓存bitmap到外部存储

public boolean putBitmap(String key, Bitmap

bitmap)

{

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 FileOutputStream

getOutputStream(String key)

{

if(mCacheDir == null)

return null;

FileOutputStream fos = new

FileOutputStream(mCacheDir.getAbsolutePath() + File.separator + key);

return fos;

}

//获取bitmap

private static BitmapFactory.Options

sBitmapOptions;

static

{

sBitmapOptions = new

BitmapFactory.Options();

sBitmapOptions.inPurgeable=true; //bitmap

can 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

原文:http://www.cnblogs.com/shaweng/p/3920693.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值