【构建Android缓存模块】(三)Controller & 异步图片加载

http://my.oschina.net/ryanhoo/blog/93432

    节课我们学习了缓存模块的实现, 缓存分做两份:Memory CacheFile Cache。方法也很简单,分别是:

  • 存储文件
  • 按唯一key值索引文件
  • 清空缓存

    区别在于内存缓存读取优先,因为它读写的速度更快。但是考虑到内存限制,退而选用文件存储,分担内存缓存的压力。

    原理非常简单,在第一课中已经详细分析了。那么要怎么才能将这个缓存模块与UI模块的显示关联起来呢?在这里我们需要一个控制器,掌管数据流向和读写,同时控制UI的显示。

    那么这个控制器需要以下的元素:

  • 内存缓存
  • 硬盘缓存
  • 异步任务处理
  • 控制UI显示
1 //caches
2 private MemoryCache memoryCache;
3 private FileCache fileCache;
4 //Asynchronous task
5 private static AsyncImageLoader imageLoader;
    Memory CacheFile Cache在上一课中有具体的实现,这里有一个异步的任务处理器—— AsyncImageDownloader,它用来在后台下载数据,完成下载后存储数据到缓存中,并更新UI的显示   。让我们来看看它是如何实现的:
01 class AsyncImageDownloader extends AsyncTask<Void, Void, Bitmap>{
02     private ImageView imageView;
03     private String fileName;
04      
05     public AsyncImageDownloader(ImageView imageView, String fileName){
06         this.imageView = imageView;
07         this.fileName = fileName;
08     }
09      
10     @Override
11     protected void onPreExecute() {
12         super.onPreExecute();
13         imageView.setImageResource(R.drawable.placeholder);
14     }
15      
16     @Override
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;
23         try {
24             if(response != null && response.getEntity() != null)
25                 in = response.getEntity().getContent();
26         catch (IllegalStateException e) {
27             e.printStackTrace();
28             return null;
29         catch (IOException e) {
30             e.printStackTrace();
31             return null;
32         }
33          
34         //TODO to be optimized: adjust the size of bitmap
35         return BitmapFactory.decodeStream(in);
36     }
37      
38     @Override
39     protected void onPostExecute(Bitmap result) {
40         super.onPostExecute(result);
41         if(result != null && imageView != null)
42             imageView.setImageBitmap(result);
43          
44         //TODO cache the bitmap both in sdcard & memory
45         memoryCache.put(fileName, result);// key is a unique token, value is the bitmap
46          
47         fileCache.put(fileName, result);
48     }
49 }

    可以看到这个类的构造函数需要两个参数,分别是文件名和对应要显示的ImageView,那么在任务开始的时候,可以为该ImageView设置未下载状态的图片,然后下载完成后更新UI。

    需要提醒的是,这里的唯一key值,我使用的是文件名,因为我接收到的文件名是唯一的。猿媛们也可以根据自己的需求,设计自己的唯一key值算法。

    接下来,我们需要读用key值索引相应的Bitmap:

01 public Bitmap getBitmap(String key){
02     Bitmap bitmap = null;
03     //1. search memory
04     bitmap = memoryCache.get(key);
05      
06     //2. search sdcard
07     if(bitmap == null){
08         File file = fileCache.getFile(key);
09         if(file != null)
10             bitmap = BitmapHelper.decodeFile(file, null);
11     }
12      
13     return bitmap;
14 }

    读取到Bitmap后进行显示:

01 public void displayBitmap(ImageView imageView, String fileName){
02     //no pic for this item
03     if(fileName == null || "".equals(fileName))
04         return;
05      
06     Bitmap bitmap = getBitmap(fileName);
07     //search in cache, if there is no such bitmap, launch downloads
08     if(bitmap != null){
09         imageView.setImageBitmap(bitmap);
10     }
11     else{
12         Log.w(TAG, "Can't find the file you required.");
13         new AsyncImageDownloader(imageView, fileName).execute();
14     }
15 }
    到这里,一个简单的缓存框架就搭建成功了。它简洁有效,但是非常单薄,似乎不够强大,需要你们根据自己的需求进行修改。另外它本来的目的就是用于演示,理解这个以后,我们再来看Google的BitmapFun。

    不过,我将它应用在一个小项目中,性能还不错。对于小项目的需求,应该是够的。

    最后,附上使用方法,以及整个类的源码。

    使用方法:

1 AsyncImageLoader imageLoader = AsyncImageLoader.getInstance(this);、
2 imageLoader.displayBitmap(imageView, fileName);

    源码:

001 <strong>public class AsyncImageLoader {
002  
003     private static final String TAG = "AsyncImageLoader";
004      
005     //caches
006     private MemoryCache memoryCache;
007     private FileCache fileCache;
008     //Asynchronous task
009     private static AsyncImageLoader imageLoader;
010  
011     class AsyncImageDownloader extends AsyncTask<Void, Void, Bitmap>{
012         private ImageView imageView;
013         private String fileName;
014          
015         public AsyncImageDownloader(ImageView imageView, String fileName){
016             this.imageView = imageView;
017             this.fileName = fileName;
018         }
019          
020         @Override
021         protected void onPreExecute() {
022             super.onPreExecute();
023             imageView.setImageResource(R.drawable.placeholder);
024         }
025          
026         @Override
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;
033             try {
034                 if(response != null && response.getEntity() != null)
035                     in = response.getEntity().getContent();
036             catch (IllegalStateException e) {
037                 e.printStackTrace();
038                 return null;
039             catch (IOException e) {
040                 e.printStackTrace();
041                 return null;
042             }
043              
044             //TODO to be optimized: adjust the size of bitmap
045             return BitmapFactory.decodeStream(in);
046         }
047          
048         @Override
049         protected void onPostExecute(Bitmap result) {
050             super.onPostExecute(result);
051             if(result != null && imageView != null)
052                 imageView.setImageBitmap(result);
053              
054             //TODO cache the bitmap both in sdcard & memory
055             memoryCache.put(fileName, result);// key is a unique token, value is the bitmap
056              
057             fileCache.put(fileName, result);
058         }
059     }
060      
061     private AsyncImageLoader(Context context){
062         this.memoryCache        =   new MemoryCache();
063         this.fileCache          =   new FileCache(context);
064     }
065      
066     public static AsyncImageLoader getInstance(Context context){
067         if(imageLoader == null)
068             imageLoader = new AsyncImageLoader(context);
069          
070         return imageLoader;
071     }
072      
073     public void displayBitmap(ImageView imageView, String fileName){
074         //no pic for this item
075         if(fileName == null || "".equals(fileName))
076             return;
077          
078         Bitmap bitmap = getBitmap(fileName);
079         //search in cache, if there is no such bitmap, launch downloads
080         if(bitmap != null){
081             imageView.setImageBitmap(bitmap);
082         }
083         else{
084             Log.w(TAG, "Can't find the file you required.");
085             new AsyncImageDownloader(imageView, fileName).execute();
086         }
087     }
088      
089     public Bitmap getBitmap(String key){
090         Bitmap bitmap = null;
091         //1. search memory
092         bitmap = memoryCache.get(key);
093          
094         //2. search sdcard
095         if(bitmap == null){
096             File file = fileCache.getFile(key);
097             if(file != null)
098                 bitmap = BitmapHelper.decodeFile(file, null);
099         }
100          
101         return bitmap;
102     }
103      
104     public void clearCache(){
105         if(memoryCache != null)
106             memoryCache.clear();
107         if(fileCache != null)
108             fileCache.clear();
109     }
110 }</strong>


源码:

附上源码,不过服务器的源码暂时还没有放出来,先看看客户端的吧。

https://github.com/ryanhoo/SoftRead

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值