转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-)
http://my.oschina.net/ryanhoo/blog/93432
上节课我们学习了缓存模块的实现, 缓存分做两份: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
http://yunpan.cn/cyLK68AM9bWGH 提取码 7198