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

来源:互联网 发布:注册域名 编辑:程序博客网 时间:2024/05/29 06:43

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

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

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

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

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

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

  • 内存缓存
  • 硬盘缓存
  • 异步任务处理
  • 控制UI显示
?
1
2
3
4
5
//caches
privateMemoryCache memoryCache;
privateFileCache fileCache;
//Asynchronous task
privatestatic 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
classAsyncImageDownloader extendsAsyncTask<Void, Void, Bitmap>{
    privateImageView imageView;
    privateString fileName;
     
    publicAsyncImageDownloader(ImageView imageView, String fileName){
        this.imageView = imageView;
        this.fileName = fileName;
    }
     
    @Override
    protectedvoid onPreExecute() {
        super.onPreExecute();
        imageView.setImageResource(R.drawable.placeholder);
    }
     
    @Override
    protectedBitmap doInBackground(Void... arg0) {
        String url = Utils.getRealUrlOfPicture(fileName);
        HttpResponse response = newHttpRetriever().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();
            returnnull;
        }catch(IOException e) {
            e.printStackTrace();
            returnnull;
        }
         
        //TODO to be optimized: adjust the size of bitmap
        returnBitmapFactory.decodeStream(in);
    }
     
    @Override
    protectedvoid 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
publicBitmap 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);
    }
     
    returnbitmap;
}

    读取到Bitmap后进行显示:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
publicvoid 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.");
        newAsyncImageDownloader(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>publicclass AsyncImageLoader {
 
    privatestatic final String TAG = "AsyncImageLoader";
     
    //caches
    privateMemoryCache memoryCache;
    privateFileCache fileCache;
    //Asynchronous task
    privatestatic AsyncImageLoader imageLoader;
 
    classAsyncImageDownloader extendsAsyncTask<Void, Void, Bitmap>{
        privateImageView imageView;
        privateString fileName;
         
        publicAsyncImageDownloader(ImageView imageView, String fileName){
            this.imageView = imageView;
            this.fileName = fileName;
        }
         
        @Override
        protectedvoid onPreExecute() {
            super.onPreExecute();
            imageView.setImageResource(R.drawable.placeholder);
        }
         
        @Override
        protectedBitmap doInBackground(Void... arg0) {
            String url = Utils.getRealUrlOfPicture(fileName);
            HttpResponse response = newHttpRetriever().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();
                returnnull;
            }catch(IOException e) {
                e.printStackTrace();
                returnnull;
            }
             
            //TODO to be optimized: adjust the size of bitmap
            returnBitmapFactory.decodeStream(in);
        }
         
        @Override
        protectedvoid 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);
        }
    }
     
    privateAsyncImageLoader(Context context){
        this.memoryCache        =   newMemoryCache();
        this.fileCache          =   newFileCache(context);
    }
     
    publicstatic AsyncImageLoader getInstance(Context context){
        if(imageLoader == null)
            imageLoader = newAsyncImageLoader(context);
         
        returnimageLoader;
    }
     
    publicvoid 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.");
            newAsyncImageDownloader(imageView, fileName).execute();
        }
    }
     
    publicBitmap 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);
        }
         
        returnbitmap;
    }
     
    publicvoid clearCache(){
        if(memoryCache != null)
            memoryCache.clear();
        if(fileCache != null)
            fileCache.clear();
    }
}</strong>


源码:

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

https://github.com/ryanhoo/SoftRead

0 0