本站已关停,现有内容仅作科研等非赢利用途使用。特此声明。
查看: 6261|回复: 2
打印 上一主题 下一主题

[Android分享]Disk cache

[复制链接]
跳转到指定楼层
1#
发表于 2013-3-28 16:37:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
之前讲的[Android分享] Memory cache

在需要快速的获取之前显示的图片,Memory cache机制是非常有用的。然而你不能保证图片是否存在Memory cache中。像
GridView 这种控件可能具有很多图片需要显示,很快图片数据就填满了缓存容量。你的App可能会被另一个任务中断。如打进来电话,你的App进入到后台,在这期间很可能被杀死,Memory cache也会销毁。一旦用户返回回来,你的App又要从新开始下载图片。
在这种情况下,可以使用磁盘缓存来保存这些已经处理过的图片,当这些图片在内存缓存中不可用的时候,可以从磁盘缓存中加载从而省略了图片处理过程。当然,从磁盘中获取图片要比在内存中获取图片慢,从磁盘中读取图片的时间是不可预期的,你应当将这个操作放到后台线程中。
注意:如果一些图片使用很频繁,可以把它们存储在ContentProvider中,Android的Gallery App就是这么做的。

private DiskLruCache mDiskLruCache;
private final Object mDiskCacheLock = new Object();
private boolean mDiskCacheStarting = true;
private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
private static final String DISK_CACHE_SUBDIR = "thumbnails";

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    // Initialize memory cache
    ...
    // Initialize disk cache on background thread
    File cacheDir = getDiskCacheDir(this, DISK_CACHE_SUBDIR);
    new InitDiskCacheTask().execute(cacheDir);
    ...
}

class InitDiskCacheTask extends AsyncTask<File, Void, Void> {
    @Override
    protected Void doInBackground(File... params) {
        synchronized (mDiskCacheLock) {
            File cacheDir = params[0];
            mDiskLruCache = DiskLruCache.open(cacheDir, DISK_CACHE_SIZE);
            mDiskCacheStarting = false; // Finished initialization
            mDiskCacheLock.notifyAll(); // Wake any waiting threads
        }
        return null;
    }
}

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
    ...
    // Decode image in background.
    @Override
    protected Bitmap doInBackground(Integer... params) {
        final String imageKey = String.valueOf(params[0]);

        // Check disk cache in background thread
        Bitmap bitmap = getBitmapFromDiskCache(imageKey);

        if (bitmap == null) { // Not found in disk cache
            // Process as normal
            final Bitmap bitmap = decodeSampledBitmapFromResource(
                    getResources(), params[0], 100, 100));
        }

        // Add final bitmap to caches
        addBitmapToCache(imageKey, bitmap);

        return bitmap;
    }
    ...
}

public void addBitmapToCache(String key, Bitmap bitmap) {
    // Add to memory cache as before
    if (getBitmapFromMemCache(key) == null) {
        mMemoryCache.put(key, bitmap);
    }

    // Also add to disk cache
    synchronized (mDiskCacheLock) {
        if (mDiskLruCache != null && mDiskLruCache.get(key) == null) {
            mDiskLruCache.put(key, bitmap);
        }
    }
}

public Bitmap getBitmapFromDiskCache(String key) {
    synchronized (mDiskCacheLock) {
        // Wait while disk cache is started from background thread
        while (mDiskCacheStarting) {
            try {
                mDiskCacheLock.wait();
            } catch (InterruptedException e) {}
        }
        if (mDiskLruCache != null) {
            return mDiskLruCache.get(key);
        }
    }
    return null;
}

// Creates a unique subdirectory of the designated app cache directory. Tries to use external
// but if not mounted, falls back on internal storage.
public static File getDiskCacheDir(Context context, String uniqueName) {
    // Check if media is mounted or storage is built-in, if so, try and use external cache dir
    // otherwise use internal cache dir
    final String cachePath =
            Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
                    !isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() :
                            context.getCacheDir().getPath();

    return new File(cachePath + File.separator + uniqueName);
}


上面代码中,初始化Disk Cache会有一些磁盘操作,因此不要把初始化操作放在主线程。这样做会有一个问题:在初始化还没有完成,App就会到DiskCache中去取数据。为了解决这个问题,上面代码使用了对象锁。从而保证了只有初始化完后,才可以读取Disk cache。

DiskLruCache类没有对外公开,如果你有Android源码,可以在源码中找到。

在实际的开发中,Memory cache 和 Disk cache很多情况下都是混合使用。首先从Memory cache读取,如果不存在再从Disk cache读取。。。


ChinaGDG.com
回复

使用道具 举报

2#
发表于 2014-7-2 22:17:16 | 只看该作者
感觉很棒!试试先
ChinaGDG.com
回复 支持 反对

使用道具 举报

3#
发表于 2014-10-10 13:08:01 | 只看该作者
学习了。
ChinaGDG.com
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表