cache-1

来源:互联网 发布:白苹果怎么备份数据 编辑:程序博客网 时间:2024/05/22 11:49

【转】http://www.jxmfkj.com/archives/189


假设你开发了一个聊天程序,它的好友列表中显示从网络获取的好友头像。可是如果用户发现每次进入好友列表的时候,程序都要重新下载头像才能进行显示,甚至当把列表滑动到底部再重新滑动回顶部的时候,刚才已经加载完成了的头像竟然又变成了空白图片开始重新加载,这将是一种糟糕的用户体验。为了解决这种问题,你需要使用高速缓存技术——Cache。

什么是Cache?

Cache,高速缓存,原意是指计算机中一块比内存更高速容量更小的存储器。更广义地说,Cache指对于最近使用过的信息的可高速读取的存储块。而本文要讲的Cache技术,指的就是将最近使用过的Bitmap缓存在手机的内存与磁盘中,来实现再次使用Bitmap时的瞬时加载,以节省用户的时间和手机流量。

下面将针对Android中的两种Cache类型Memory Cache和Disk Cache分别进行介绍。样例代码取自Android开发者站。

1/2:Memory Cache内存中的Cache

Memory Cache使用内存来为应用程序提供Cache。由于内存的读写速度非常快,所以我们应该优先使用它(相对于下面将介绍的Disk Cache来说)。

Android中提供了LruCache类来进行Memory Cache的管理(该类是在Android 3.1时推出的,但我们可以使用android -support-v4.jar的兼容包来对低版本的手机提供支持)。

提示:有人习惯使用SoftReference和WeakReference来做Memory Cache,但谷歌官方不建议这么做。因为自从Android2.3之后,Android中的GC变得更加积极,导致这种做法中缓存的Bitmaps非常容易被回收掉;另外,在Android3.0之前,Bitmap的数据是直接分配在native memory中,它的释放是不受dalvik控制的,因此更容易导致内存的溢出。如果你喜欢简单粗暴的总结,那就是:反正不要用这种方法来管理Memory Cache。

下面我们看一段为Bitmap设置LruCache的代码

 

01private LruCache<String, Bitmap> mMemoryCache;
02 
03@Override
04protected void onCreate(Bundle savedInstanceState) {
05    ...
06    // 获取虚拟机可用内存(内存占用超过该值的时候,将报OOM异常导致程序崩溃)。最后除以1024是为了以kb为单位
07    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
08 
09    // 使用可用内存的1/8来作为Memory Cache
10    final int cacheSize = maxMemory / 8;
11 
12    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
13        @Override
14        protected int sizeOf(String key, Bitmap bitmap) {
15            // 重写sizeOf()方法,使用Bitmap占用内存的kb数作为LruCache的size
16            return bitmap.getByteCount() / 1024;
17        }
18    };
19    ...
20}
21 
22public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
23    if (getBitmapFromMemCache(key) == null) {
24        mMemoryCache.put(key, bitmap);
25    }
26}
27 
28public Bitmap getBitmapFromMemCache(String key) {
29    return mMemoryCache.get(key);
30}

提示:在以上代码中,我们使用了可用内存的1/8来提供给Memory Cache,我们简单分析一下这个值。一个普通屏幕尺寸、hdpi的手机的可用内存为32M,那么他的Memory Cache为32M/8=4M。通常hdpi的手机为480*800像素,它一个全屏Bitmap占用内存为480*800*4B=1536400B≈1.5M。那么4M的内存为大约2.5个屏幕大小的bitmap提供缓存。同理,一个普通尺寸、xhdpi大小的720*1280的手机可以为大约2.2个屏幕大小的bitmap提供缓存。

当一个ImageView需要设置一个bitmap的时候,LruCache会进行检查,如果它已经缓存了相应的bitmap,它就直接取出来并设置给这个ImageView;否则,他将启动一个后台线程加载这个Bitmap

 

01public void loadBitmap(int resId, ImageView imageView) {
02    final String imageKey = String.valueOf(resId);
03 
04    final Bitmap bitmap = getBitmapFromMemCache(imageKey);
05    if (bitmap != null) {
06        mImageView.setImageBitmap(bitmap);
07    else {
08        mImageView.setImageResource(R.drawable.image_placeholder);
09        BitmapWorkerTask task = new BitmapWorkerTask(mImageView);
10        task.execute(resId);
11    }
12}

BitmapWorkerTask在加载完成后,通过前面的addBitmapToMemoryCache()方法把这个bitmap进行缓存:

 

01class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
02    ...
03    // 后台加载Bitmap
04    @Override
05    protected Bitmap doInBackground(Integer... params) {
06        final Bitmap bitmap = decodeSampledBitmapFromResource(
07                getResources(), params[0], 100100));
08        addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);
09        return bitmap;
10    }
11    ...
12}


0 0