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

来源:互联网 发布:述职报告 知乎 编辑:程序博客网 时间:2024/05/23 16:48

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

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

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

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

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

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

  • 内存缓存
  • 硬盘缓存
  • 异步任务处理
  • 控制UI显示
1//caches
2private MemoryCache memoryCache;
3private FileCache fileCache;
4//Asynchronous task
5private static AsyncImageLoader imageLoader;
    Memory CacheFile Cache在上一课中有具体的实现,这里有一个异步的任务处理器——AsyncImageDownloader,它用来在后台下载数据,完成下载后存储数据到缓存中,并更新UI的显示 。让我们来看看它是如何实现的:
01class 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:

01public 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后进行显示:

01public 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。

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

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

    使用方法:

1AsyncImageLoader imageLoader = AsyncImageLoader.getInstance(this);、
2imageLoader.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

原创粉丝点击