上节课我们学习了缓存模块的实现, 缓存分做两份:Memory Cache和File Cache。方法也很简单,分别是:
区别在于内存缓存读取优先,因为它读写的速度更快。但是考虑到内存限制,退而选用文件存储,分担内存缓存的压力。
原理非常简单,在第一课中已经详细分析了。那么要怎么才能将这个缓存模块与UI模块的显示关联起来呢?在这里我们需要一个控制器,掌管数据流向和读写,同时控制UI的显示。
那么这个控制器需要以下的元素:
2 | private MemoryCache memoryCache; |
3 | private FileCache fileCache; |
5 | private static AsyncImageLoader imageLoader; |
Memory Cache和File Cache在上一课中有具体的实现,这里有一个异步的任务处理器——
AsyncImageDownloader,它用来在后台下载数据,完成下载后存储数据到缓存中,并更新UI的显示
。让我们来看看它是如何实现的:
01 | class AsyncImageDownloader extends AsyncTask<Void, Void, Bitmap>{ |
02 | private ImageView imageView; |
03 | private String fileName; |
05 | public AsyncImageDownloader(ImageView imageView, String fileName){ |
06 | this .imageView = imageView; |
07 | this .fileName = fileName; |
11 | protected void onPreExecute() { |
13 | imageView.setImageResource(R.drawable.placeholder); |
17 | protected Bitmap doInBackground(Void... arg0) { |
18 | String url = Utils.getRealUrlOfPicture(fileName); |
19 | HttpResponse response = new HttpRetriever().requestGet(url, null ); |
20 | Log.i(TAG, "url: " + url); |
21 | Log.i(TAG, "respone: " + response); |
22 | InputStream in = null ; |
24 | if (response != null && response.getEntity() != null ) |
25 | in = response.getEntity().getContent(); |
26 | } catch (IllegalStateException e) { |
29 | } catch (IOException e) { |
35 | return BitmapFactory.decodeStream(in); |
39 | protected void onPostExecute(Bitmap result) { |
40 | super .onPostExecute(result); |
41 | if (result != null && imageView != null ) |
42 | imageView.setImageBitmap(result); |
45 | memoryCache.put(fileName, result); |
47 | fileCache.put(fileName, result); |
可以看到这个类的构造函数需要两个参数,分别是文件名和对应要显示的ImageView,那么在任务开始的时候,可以为该ImageView设置未下载状态的图片,然后下载完成后更新UI。
注:需要提醒的是,这里的唯一key值,我使用的是文件名,因为我接收到的文件名是唯一的。猿媛们也可以根据自己的需求,设计自己的唯一key值算法。
接下来,我们需要读用key值索引相应的Bitmap:
01 | public Bitmap getBitmap(String key){ |
04 | bitmap = memoryCache.get(key); |
08 | File file = fileCache.getFile(key); |
10 | bitmap = BitmapHelper.decodeFile(file, null ); |
读取到Bitmap后进行显示:
01 | public void displayBitmap(ImageView imageView, String fileName){ |
03 | if (fileName == null || "" .equals(fileName)) |
06 | Bitmap bitmap = getBitmap(fileName); |
09 | imageView.setImageBitmap(bitmap); |
12 | Log.w(TAG, "Can't find the file you required." ); |
13 | new AsyncImageDownloader(imageView, fileName).execute(); |
到这里,一个简单的缓存框架就搭建成功了。它简洁有效,但是非常单薄,似乎不够强大,需要你们根据自己的需求进行修改。另外它本来的目的就是用于演示,理解这个以后,我们再来看Google的BitmapFun。
不过,我将它应用在一个小项目中,性能还不错。对于小项目的需求,应该是够的。
最后,附上使用方法,以及整个类的源码。
使用方法:
1 | AsyncImageLoader imageLoader = AsyncImageLoader.getInstance( this );、 |
2 | imageLoader.displayBitmap(imageView, fileName); |
源码:
001 | <strong> public class AsyncImageLoader { |
003 | private static final String TAG = "AsyncImageLoader" ; |
006 | private MemoryCache memoryCache; |
007 | private FileCache fileCache; |
009 | private static AsyncImageLoader imageLoader; |
011 | class AsyncImageDownloader extends AsyncTask<Void, Void, Bitmap>{ |
012 | private ImageView imageView; |
013 | private String fileName; |
015 | public AsyncImageDownloader(ImageView imageView, String fileName){ |
016 | this .imageView = imageView; |
017 | this .fileName = fileName; |
021 | protected void onPreExecute() { |
022 | super .onPreExecute(); |
023 | imageView.setImageResource(R.drawable.placeholder); |
027 | protected Bitmap doInBackground(Void... arg0) { |
028 | String url = Utils.getRealUrlOfPicture(fileName); |
029 | HttpResponse response = new HttpRetriever().requestGet(url, null ); |
030 | Log.i(TAG, "url: " + url); |
031 | Log.i(TAG, "respone: " + response); |
032 | InputStream in = null ; |
034 | if (response != null && response.getEntity() != null ) |
035 | in = response.getEntity().getContent(); |
036 | } catch (IllegalStateException e) { |
039 | } catch (IOException e) { |
045 | return BitmapFactory.decodeStream(in); |
049 | protected void onPostExecute(Bitmap result) { |
050 | super .onPostExecute(result); |
051 | if (result != null && imageView != null ) |
052 | imageView.setImageBitmap(result); |
055 | memoryCache.put(fileName, result); |
057 | fileCache.put(fileName, result); |
061 | private AsyncImageLoader(Context context){ |
062 | this .memoryCache = new MemoryCache(); |
063 | this .fileCache = new FileCache(context); |
066 | public static AsyncImageLoader getInstance(Context context){ |
067 | if (imageLoader == null ) |
068 | imageLoader = new AsyncImageLoader(context); |
073 | public void displayBitmap(ImageView imageView, String fileName){ |
075 | if (fileName == null || "" .equals(fileName)) |
078 | Bitmap bitmap = getBitmap(fileName); |
081 | imageView.setImageBitmap(bitmap); |
084 | Log.w(TAG, "Can't find the file you required." ); |
085 | new AsyncImageDownloader(imageView, fileName).execute(); |
089 | public Bitmap getBitmap(String key){ |
090 | Bitmap bitmap = null ; |
092 | bitmap = memoryCache.get(key); |
096 | File file = fileCache.getFile(key); |
098 | bitmap = BitmapHelper.decodeFile(file, null ); |
104 | public void clearCache(){ |
105 | if (memoryCache != null ) |
107 | if (fileCache != null ) |
源码:
附上源码,不过服务器的源码暂时还没有放出来,先看看客户端的吧。
https://github.com/ryanhoo/SoftRead