原创基于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的缓存策略的主要内容,如果未能解决你的问题,请参考以下文章
Android照片墙完整版,完美结合LruCache和DiskLruCache
手摸手教你用 TypeScript 写一个基于 Proxy 的缓存库