原创基于Volley和DiskLruCache的缓存策略

Posted 优才网

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原创基于Volley和DiskLruCache的缓存策略相关的知识,希望对你有一定的参考价值。

在我们开发应用过程中,不可避免的使用网络图片,那么图片请求和缓存就成了一个问题,本着为用户节省流量的角度,我们的应用就应该是已经下载的图片不会重复下载,以及下载过的图片没有网络也能查看的效果,这里就涉及到了网络请求、内存缓存和磁盘缓存。


简单的介绍一下今天的两位主角:
:是基于Lru磁盘缓存的Java实现。

:Google推出的android异步网络请求框架和图片加载框架(自备梯子)。

细心的小伙伴应该发现咋是两个主角呢,说好的内存缓存呢?其实在Volley中已经默认实现内存缓存了,我们简单的介绍下Volley的接口及关键函数(以下为引用)。

ImageLoader

ImageLoader类需要一个请求的实例以及一个ImageCache类的实现。图片通过传递一个URL和一个ImageListener实例到get()方法进行加载。从那里,ImageLoader检查ImageCache,如果图像不是在缓存中,就从网络中加载图片。

NetworkImageView

这个类代替布局中的ImageViews类,而且需要使用ImageLoader类。NetworkImageView类的setUrl()方法需要一个URL路径字符串和一个ImageLoader实例。然后使用ImageLoder的get()方法来获取图片数据。

<com.android.volley.toolbox.NetworkImageView
    android:id="@+id/twitterUserImage"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:layout_width="40dp"
    android:layout_height="40dp"
    android:padding="5dp"
    />
ImageCache

Volley库的ImageCache接口允许你使用你喜好的L1缓存实现。

ImageCache接口有两个方法,getBitmap(String url)和putBitmap(String url, Bitmap bitmap)。这些桩是非常简单的,它们可以添加到任何缓存实现里。

有两种可用的缓存实现。推荐的方法是在内存中使用一个基础的LRU缓存。对于硬盘的缓存实现,我选择使用Jack Wharton编写的DiskLruCache。我选择这个实现是因为它在Android社区中被频繁的使用。使用一个基于磁盘的L1缓存可能导致阻塞I/O问题。Volley已经有一个隐式的硬盘L2缓存。硬盘L1缓存已经被包含在内了。

原生项目的介绍如下
以下是这个实现的主要组件:

RequestManager

RequestManager维护我们的RequestQueue的一个引用。Volley使用ResuestQueue来处理我们对Twitter数据和图片加载的请求。

GsonRequest

GsonRequest与图片加载没有直接联系,但它代表了如何扩展Volley请求类来处理JSON解析。该类用于对Twitter的GET请求和TwitterData对象的结果。

BitmapLruImageCache

该类是一个基本的“最近最少使用(LRU)”内存缓存实现。它速度快但不会阻塞I/O。这是推荐的方法。

DiskLruImageCache

DiskLruImageCache是一个位图版本的DiskLruCache封装。它从DiskLruCache中增加并检索位图,还处理缓存的实例化。硬盘缓存可能会造成I/O阻塞。

ImageCacheManager

ImageCacheManager持有ImageCache和Volley ImageLoader引用。

在ImageCacheManager中,你可能注意到一点就是我们使用URL字符串的hashCode()作为缓存的键值。这是由于URL中的某些字符不能作为缓存的键值。

BuzzArrayAdapter

该适配器比较简单的。这里只需要注意一点,我们要实现Volley的Listener和ErrorListener接口,并且把该适配器作为Listener参数传递给了NetworkImageView 的 setUrl(String string , Listener listener, ErrorListener errorListener) 方法。这个适配器包含了一些额外代码用于滚动时加载旧的tweets。

以上就是原博的内容,我们的改造是基于来进行的。

首先来介绍下具体的思路,如图:

1.首先改造的是项目中缓存的实现,需要修改为磁盘和内存同时使用。

在ImageCacheManager中删除CacheType的两种枚举类型,并添加磁盘缓存的实现对象,然后修改实例化的方法,如下:

/** * Image cache implementation */private BitmapLruImageCache mMemoryCache;/** * Volley image loader */private ImageLoader mImageLoader;/** * Image disk cache implementation */private DiskLruImageCache mDiskCache;/** * Initializer for the manager. Must be called prior to use. * * @param context *   application context * @param uniqueName *   name for the cache location * @param cacheSize *   max size for the cache * @param compressFormat *   file type compression format. * @param quality */public void init(Context context, String uniqueName, int cacheSize, CompressFormat compressFormat, int quality){
    mDiskCache= new DiskLruImageCache(context, uniqueName, cacheSize, compressFormat, quality);
    mMemoryCache = new BitmapLruImageCache(cacheSize);
    mImageLoader = new ImageLoader(RequestManager.getRequestQueue(), mMemoryCache);
}

需要说明的是,这里可以看成只增加了DiskLruImageCache的实例,Volley原生的使用内存加载请求图片的逻辑方法并没有改变,所以你如果想对自己现有的项目修改,则只需添加DiskLruImageCache的实例即可。

2.修改MainApplication中初始化的方法
/** * Create the image cache. Uses Memory Cache by default. Change to Disk for a Disk based LRU implementation.   */private void createImageCache(){
ImageCacheManager.getInstance().init(this,"pic", DISK_IMAGECACHE_SIZE
, DISK_IMAGECACHE_COMPRESS_FORMAT
, DISK_IMAGECACHE_QUALITY);
}
    /**     * Get a usable cache directory (external if available, internal otherwise).     * 根据传入的uniqueName获取硬盘缓存的路径地址。     * @param context     *            The context to use     * @param uniqueName     *            A unique directory name to append to the cache dir     * @return The cache dir     */
    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
        String cachePath;        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
                || !Environment.isExternalStorageRemovable()) {
            cachePath = context.getExternalCacheDir().getPath();
        } else {
            cachePath = context.getCacheDir().getPath();
        }        return new File(cachePath + File.separator + uniqueName);
    }
3. 修改获取和添加图片的逻辑

上面的准备工作做完,我们就只差一步就成功了。
上面也说道,这次修改没有改变Volley原生加载图片的方法,所以我们只需要在获取和添加图片的地方做些小改动就可以,这里默认使用的是内存缓存图片的方法,所以修改的是BitmapLruImageCache类,如下:

@Overridepublic Bitmap getBitmap(String url) {
Log.v(TAG, "Retrieved item from Mem Cache");
    Bitmap bitmap = get(url);    //如果没有在内存中找到则去磁盘缓存查找
    if(bitmap==null){
        bitmap = ImageCacheManager.getInstance().getBitmap(url);        //如果磁盘缓存找到,添加到内存缓存中
        if(bitmap!=null){
            putBitmap(url,bitmap);
        }
    }return bitmap;
}@Overridepublic void putBitmap(String url, Bitmap bitmap) {    //在getBitmap方法返回NULL时,Volley启动下载图片的任务下载图片成功后会调用此方法Log.v(TAG, "Added item to Mem Cache");    //原生的内存缓存添加图片到内存中的方法put(url, bitmap);    //将图片同时添加到磁盘缓存中
    ImageCacheManager.getInstance().putBitmap(url,bitmap);
}

以上就是全部的修改啦,很简单吧。
里面的例子是下载Tweets数据的,可以修改为你自己项目的数据,学以致用,赶紧去实践吧。

参考:


推荐阅读↓








以上是关于原创基于Volley和DiskLruCache的缓存策略的主要内容,如果未能解决你的问题,请参考以下文章

手写一个基于 Proxy 的缓存库

Android照片墙完整版,完美结合LruCache和DiskLruCache

手摸手教你用 TypeScript 写一个基于 Proxy 的缓存库

Android-DiskLruCache

使用LruCache和DiskLruCache手写一个ImageLoader

Volley框架的使用