转载自:http://my.oschina.net/ryanhoo/blog/93432
上节课我们学习了缓存模块的实现, 缓存分做两份:Memory Cache和File Cache。方法也很简单,分别是:
- 存储文件
- 按唯一key值索引文件
- 清空缓存
区别在于内存缓存读取优先,因为它读写的速度更快。但是考虑到内存限制,退而选用文件存储,分担内存缓存的压力。
原理非常简单,在第一课中已经详细分析了。那么要怎么才能将这个缓存模块与UI模块的显示关联起来呢?在这里我们需要一个控制器,掌管数据流向和读写,同时控制UI的显示。
那么这个控制器需要以下的元素:
- 内存缓存
- 硬盘缓存
- 异步任务处理
- 控制UI显示
1
2
3
4
5
|
//caches
private
MemoryCache memoryCache;
private
FileCache fileCache;
//Asynchronous task
private
static
AsyncImageLoader imageLoader;
|
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();
}
}
|
不过,我将它应用在一个小项目中,性能还不错。对于小项目的需求,应该是够的。
最后,附上使用方法,以及整个类的源码。
使用方法:
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