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

转载自:http://my.oschina.net/ryanhoo/blog/93432

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

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

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

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

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

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

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Bitmap getBitmap(String key){
     Bitmap bitmap = null ;
     //1. search memory
     bitmap = memoryCache.get(key);
     
     //2. search sdcard
     if (bitmap == null ){
         File file = fileCache.getFile(key);
         if (file != null )
             bitmap = BitmapHelper.decodeFile(file, null );
     }
     
     return bitmap;
}

    读取到Bitmap后进行显示:

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

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

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

    使用方法:

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

    源码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
<strong> public class AsyncImageLoader {
 
     private static final String TAG = "AsyncImageLoader" ;
     
     //caches
     private MemoryCache memoryCache;
     private FileCache fileCache;
     //Asynchronous task
     private static AsyncImageLoader imageLoader;
 
     class AsyncImageDownloader extends AsyncTask<Void, Void, Bitmap>{
         private ImageView imageView;
         private String fileName;
         
         public AsyncImageDownloader(ImageView imageView, String fileName){
             this .imageView = imageView;
             this .fileName = fileName;
         }
         
         @Override
         protected void onPreExecute() {
             super .onPreExecute();
             imageView.setImageResource(R.drawable.placeholder);
         }
         
         @Override
         protected Bitmap doInBackground(Void... arg0) {
             String url = Utils.getRealUrlOfPicture(fileName);
             HttpResponse response = new HttpRetriever().requestGet(url, null );
             Log.i(TAG, "url: " + url);
             Log.i(TAG, "respone: " + response);
             InputStream in = null ;
             try {
                 if (response != null && response.getEntity() != null )
                     in = response.getEntity().getContent();
             } catch (IllegalStateException e) {
                 e.printStackTrace();
                 return null ;
             } catch (IOException e) {
                 e.printStackTrace();
                 return null ;
             }
             
             //TODO to be optimized: adjust the size of bitmap
             return BitmapFactory.decodeStream(in);
         }
         
         @Override
         protected void onPostExecute(Bitmap result) {
             super .onPostExecute(result);
             if (result != null && imageView != null )
                 imageView.setImageBitmap(result);
             
             //TODO cache the bitmap both in sdcard & memory
             memoryCache.put(fileName, result); // key is a unique token, value is the bitmap
             
             fileCache.put(fileName, result);
         }
     }
     
     private AsyncImageLoader(Context context){
         this .memoryCache        =   new MemoryCache();
         this .fileCache          =   new FileCache(context);
     }
     
     public static AsyncImageLoader getInstance(Context context){
         if (imageLoader == null )
             imageLoader = new AsyncImageLoader(context);
         
         return imageLoader;
     }
     
     public void displayBitmap(ImageView imageView, String fileName){
         //no pic for this item
         if (fileName == null || "" .equals(fileName))
             return ;
         
         Bitmap bitmap = getBitmap(fileName);
         //search in cache, if there is no such bitmap, launch downloads
         if (bitmap != null ){
             imageView.setImageBitmap(bitmap);
         }
         else {
             Log.w(TAG, "Can't find the file you required." );
             new AsyncImageDownloader(imageView, fileName).execute();
         }
     }
     
     public Bitmap getBitmap(String key){
         Bitmap bitmap = null ;
         //1. search memory
         bitmap = memoryCache.get(key);
         
         //2. search sdcard
         if (bitmap == null ){
             File file = fileCache.getFile(key);
             if (file != null )
                 bitmap = BitmapHelper.decodeFile(file, null );
         }
         
         return bitmap;
     }
     
     public void clearCache(){
         if (memoryCache != null )
             memoryCache.clear();
         if (fileCache != null )
             fileCache.clear();
     }
}</strong>


源码:

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

https://github.com/ryanhoo/SoftRead

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值