注意:在过去,一个常用的内存缓存实现是一个SoftReference或WeakReference的位图缓存,然而现在不推荐使用.从android2.3(API 级别9)开始,垃圾回收器更加注重于回收软/弱引用,这使得使用以上引用很大程度上无效.此外,之前的android3.0(API级别11),位图的备份数据存储在本地那些在一种可预测的情况下没有被释放的内存中,很有可能会导致应用程序内存溢出和崩溃.
为了选择一个合适的的LruCache大小,许多因素应当被予以考虑,例如:
其余的活动或者应用程序都是很耗内存的嘛?
大量的图片是如何立刻出现在屏幕上的?需要多少即将在屏幕上显示的?
设备的屏幕的大小和分辨率是多少?一个额外的高密度屏(xhdpi)设备,例如Galaxy Nexus 将需要一个更大的缓存来维持内存中相同数量的图片,与像Nexus S (hdpi)设备比较起来.
位图是什么尺寸和配置以及每张图片要占用多少内存?
图片访问频繁嘛?比起别的将会被频繁地访问吗?也许你可能总是想要在内存中保存一定项,甚至对于不同的位图组来说有多个LRUCache对象.
你能在数量和质量之间取得平衡嘛?有时对于存储更多的低质量的位图是更有用的,潜在地在另外的后台任务中加载一个更高质量版本.
没有具体的大小以及适合所有应用程序的公式,它是由你来分析您的使用情况,并拿出一个合适的解决方案.缓存太小会导致额外的没有益处的开销,缓存过大会再次导致java.lang.OutOfMemory异常,并且只保留下你的应用程序其余相当少的内存来运行你的应用程序. 这个例子是针对位图来设置一个LruCache:
private LruCache mMemoryCache; @Override protected void onCreate(Bundle savedInstanceState) { ... // Get memory class of this device, exceeding this amount will throw an // OutOfMemory exception. final int memClass = ((ActivityManager) context.getSystemService( Context.ACTIVITY_SERVICE)).getMemoryClass(); // Use 1/8th of the available memory for this memory cache. final int cacheSize = 1024 * 1024 * memClass / 8; mMemoryCache = new LruCache(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { // The cache size will be measured in bytes rather than number of items. return bitmap.getByteCount(); } }; ... } public void addBitmapToMemoryCache(String key, Bitmap bitmap) { if (getBitmapFromMemCache(key) == null) { mMemoryCache.put(key, bitmap); } } public Bitmap getBitmapFromMemCache(String key) { return mMemoryCache.get(key); }
注意:在这个例子中,应用程序中八分之一的内存被用作缓存.在一个普通的/hdpi设备中最低有4MB.在一个800* 480分辨率的设备上全屏显示一个充满图片的GridView控件视图将使用1.5MB左右的缓存,所以这将在内存中缓冲至少四分之一的图片.
当将一张位图加载进一个ImageView中,LruCache首先被检查.如果有输入,缓存立刻被使用来更新这个ImageView视图,另外一个后台线程随之诞生来处理这张图片:
public void loadBitmap(int resId, ImageView imageView) { final String imageKey = String.valueOf(resId); final Bitmap bitmap = getBitmapFromMemCache(imageKey); if (bitmap != null) { mImageView.setImageBitmap(bitmap); } else { mImageView.setImageResource(R.drawable.image_placeholder); BitmapWorkerTask task = new BitmapWorkerTask(mImageView); task.execute(resId); } }
BitmapWorkerTask也需要被更新添加到内存缓冲项中:
class BitmapWorkerTask extends AsyncTask { ... // Decode image in background. @Override protected Bitmap doInBackground(Integer... params) { final Bitmap bitmap = decodeSampledBitmapFromResource( getResources(), params[0], 100, 100)); addBitmapToMemoryCache(String.valueOf(params[0]), bitmap); return bitmap; } ... }