Android异步加载图像(含线程池,缓存方法)
来源:互联网 发布:邮箱反查域名 编辑:程序博客网 时间:2024/06/04 18:14
研究了android从网络上异步加载图像:
(1)由于android UI更新支持单一线程原则,所以从网络上取数据并更新到界面上,为了不阻塞主线程首先可能会想到以下方法。
在主线程中new 一个Handler对象,加载图像方法如下所示
01
private
void
loadImage(
final
String url,
final
int
id) {
02
handler.post(
new
Runnable() {
03
public
void
run() {
04
Drawable drawable =
null
;
05
try
{
06
drawable = Drawable.createFromStream(
new
URL(url).openStream(),
"image.png"
);
07
}
catch
(IOException e) {
08
}
09
((ImageView) LazyLoadImageActivity.
this
.findViewById(id)).setImageDrawable(drawable);
10
}
11
});
12
}
上面这个方法缺点很显然,经测试,如果要加载多个图片,这并不能实现异步加载,而是等到所有的图片都加载完才一起显示,因为它们都运行在一个线程中。
然后,我们可以简单改进下,将Handler+Runnable模式改为Handler+Thread+Message模式不就能实现同时开启多个线程吗?
(2)在主线程中new 一个Handler对象,代码如下:
1
final
Handler handler2=
new
Handler(){
2
@Override
3
public
void
handleMessage(Message msg) {
4
((ImageView) LazyLoadImageActivity.
this
.findViewById(msg.arg1)).setImageDrawable((Drawable)msg.obj);
5
}
6
};
对应加载图像代码如下:对应加载图像代码如下:对应加载图像代码如下:
01
// 引入线程池来管理多线程
02
private
void
loadImage3(
final
String url,
final
int
id) {
03
executorService.submit(
new
Runnable() {
04
public
void
run() {
05
try
{
06
final
Drawable drawable = Drawable.createFromStream(
new
URL(url).openStream(),
"image.png"
);
07
handler.post(
new
Runnable() {
08
09
public
void
run() {
10
((ImageView) LazyLoadImageActivity.
this
.findViewById(id)).setImageDrawable(drawable);
11
}
12
});
13
}
catch
(Exception e) {
14
throw
new
RuntimeException(e);
15
}
16
}
17
});
18
}
(4)为了更方便使用我们可以将异步加载图像方法封装一个类,对外界只暴露一个方法即可,考虑到效率问题我们可以引入内存缓存机制,做法是
建立一个HashMap,其键(key)为加载图像url,其值(value)是图像对象Drawable。先看一下我们封装的类
01
public
class
AsyncImageLoader3 {
02
//为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动)
03
public
Map<String, SoftReference<Drawable>> imageCache =
new
HashMap<String, SoftReference<Drawable>>();
04
private
ExecutorService executorService = Executors.newFixedThreadPool(
5
);
//固定五个线程来执行任务
05
private
final
Handler handler=
new
Handler();
06
07
/**
08
*
09
* @param imageUrl 图像url地址
10
* @param callback 回调接口
11
* @return 返回内存中缓存的图像,第一次加载返回null
12
*/
13
public
Drawable loadDrawable(
final
String imageUrl,
final
ImageCallback callback) {
14
//如果缓存过就从缓存中取出数据
15
if
(imageCache.containsKey(imageUrl)) {
16
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
17
if
(softReference.get() !=
null
) {
18
return
softReference.get();
19
}
20
}
21
//缓存中没有图像,则从网络上取出数据,并将取出的数据缓存到内存中
22
executorService.submit(
new
Runnable() {
23
public
void
run() {
24
try
{
25
final
Drawable drawable = Drawable.createFromStream(
new
URL(imageUrl).openStream(),
"image.png"
);
26
27
imageCache.put(imageUrl,
new
SoftReference<Drawable>(drawable));
28
29
handler.post(
new
Runnable() {
30
public
void
run() {
31
callback.imageLoaded(drawable);
32
}
33
});
34
}
catch
(Exception e) {
35
throw
new
RuntimeException(e);
36
}
37
}
38
});
39
return
null
;
40
}
41
//从网络上取数据方法
42
protected
Drawable loadImageFromUrl(String imageUrl) {
43
try
{
44
return
Drawable.createFromStream(
new
URL(imageUrl).openStream(),
"image.png"
);
45
}
catch
(Exception e) {
46
throw
new
RuntimeException(e);
47
}
48
}
49
//对外界开放的回调接口
50
public
interface
ImageCallback {
51
//注意 此方法是用来设置目标对象的图像资源
52
public
void
imageLoaded(Drawable imageDrawable);
53
}
54
}
这样封装好后使用起来就方便多了。在主线程中首先要引入AsyncImageLoader3 对象,然后直接调用其loadDrawable方法即可,需要注意的是ImageCallback接口的imageLoaded方法是唯一可以把加载的图像设置到目标ImageView或其相关的组件上。
在主线程调用代码:
先实例化对象 private AsyncImageLoader3 asyncImageLoader3 = new AsyncImageLoader3();
调用异步加载方法:
01
//引入线程池,并引入内存缓存功能,并对外部调用封装了接口,简化调用过程
02
private
void
loadImage4(
final
String url,
final
int
id) {
03
//如果缓存过就会从缓存中取出图像,ImageCallback接口中方法也不会被执行
04
Drawable cacheImage = asyncImageLoader.loadDrawable(url,
new
AsyncImageLoader.ImageCallback() {
05
//请参见实现:如果第一次加载url时下面方法会执行
06
public
void
imageLoaded(Drawable imageDrawable) {
07
((ImageView) findViewById(id)).setImageDrawable(imageDrawable);
08
}
09
});
10
if
(cacheImage!=
null
){
11
((ImageView) findViewById(id)).setImageDrawable(cacheImage);
12
}
13
}
5)同理,下面也给出采用Thread+Handler+MessageQueue+内存缓存代码,原则同(4),只是把线程池换成了Thread+Handler+MessageQueue模式而已。代码如下:5)同理,下面也给出采用Thread+Handler+MessageQueue+内存缓存代码,原则同(4),只是把线程池换成了Thread+Handler+MessageQueue模式而已。代码如下:
01
public
class
AsyncImageLoader {
02
//为了加快速度,加入了缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动)
03
private
Map<String, SoftReference<Drawable>> imageCache =
new
HashMap<String, SoftReference<Drawable>>();
04
05
/**
06
*
07
* @param imageUrl 图像url地址
08
* @param callback 回调接口
09
* @return 返回内存中缓存的图像,第一次加载返回null
10
*/
11
public
Drawable loadDrawable(
final
String imageUrl,
final
ImageCallback callback) {
12
//如果缓存过就从缓存中取出数据
13
if
(imageCache.containsKey(imageUrl)) {
14
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
15
if
(softReference.get() !=
null
) {
16
return
softReference.get();
17
}
18
}
19
20
final
Handler handler =
new
Handler() {
21
@Override
22
public
void
handleMessage(Message msg) {
23
callback.imageLoaded((Drawable) msg.obj);
24
}
25
};
26
new
Thread() {
27
public
void
run() {
28
Drawable drawable = loadImageFromUrl(imageUrl);
29
imageCache.put(imageUrl,
new
SoftReference<Drawable>(drawable));
30
handler.sendMessage(handler.obtainMessage(
0
, drawable));
31
32
}
33
34
}.start();
35
/*
36
下面注释的这段代码是Handler的一种代替方法
37
*/
38
// new AsyncTask() {
39
// @Override
40
// protected Drawable doInBackground(Object... objects) {
41
// Drawable drawable = loadImageFromUrl(imageUrl);
42
// imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
43
// return drawable;
44
// }
45
//
46
// @Override
47
// protected void onPostExecute(Object o) {
48
// callback.imageLoaded((Drawable) o);
49
// }
50
// }.execute();
51
return
null
;
52
}
53
54
protected
Drawable loadImageFromUrl(String imageUrl) {
55
try
{
56
return
Drawable.createFromStream(
new
URL(imageUrl).openStream(),
"src"
);
57
}
catch
(Exception e) {
58
throw
new
RuntimeException(e);
59
}
60
}
61
//对外界开放的回调接口
62
public
interface
ImageCallback {
63
public
void
imageLoaded(Drawable imageDrawable);
64
}
65
}
至此,异步加载就介绍完了,下面给出的代码为测试用的完整代码:
001
package
com.bshark.supertelphone.activity;
002
003
import
android.app.Activity;
004
import
android.graphics.drawable.Drawable;
005
import
android.os.Bundle;
006
import
android.os.Handler;
007
import
android.os.Message;
008
import
android.widget.ImageView;
009
import
com.bshark.supertelphone.R;
010
import
com.bshark.supertelphone.ui.adapter.util.AsyncImageLoader;
011
import
com.bshark.supertelphone.ui.adapter.util.AsyncImageLoader3;
012
013
import
java.io.IOException;
014
import
java.net.URL;
015
import
java.util.concurrent.ExecutorService;
016
import
java.util.concurrent.Executors;
017
018
public
class
LazyLoadImageActivity
extends
Activity {
019
final
Handler handler=
new
Handler();
020
final
Handler handler2=
new
Handler(){
021
@Override
022
public
void
handleMessage(Message msg) {
023
((ImageView) LazyLoadImageActivity.
this
.findViewById(msg.arg1)).setImageDrawable((Drawable)msg.obj);
024
}
025
};
026
private
ExecutorService executorService = Executors.newFixedThreadPool(
5
);
//固定五个线程来执行任务
027
private
AsyncImageLoader asyncImageLoader =
new
AsyncImageLoader();
028
private
AsyncImageLoader3 asyncImageLoader3 =
new
AsyncImageLoader3();
029
030
031
@Override
032
public
void
onCreate(Bundle savedInstanceState) {
033
super
.onCreate(savedInstanceState);
034
setContentView(R.layout.main);
035
036
// loadImage("http://www.chinatelecom.com.cn/images/logo_new.gif", R.id.image1);
037
// loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.image2);
038
// loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.image3);
039
// loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.image4);
040
// loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.image5);
041
042
loadImage2(
"http://www.chinatelecom.com.cn/images/logo_new.gif"
, R.id.image1);
043
loadImage2(
"http://www.baidu.com/img/baidu_logo.gif"
, R.id.image2);
044
loadImage2(
"http://cache.soso.com/30d/img/web/logo.gif"
, R.id.image3);
045
loadImage2(
"http://www.baidu.com/img/baidu_logo.gif"
, R.id.image4);
046
loadImage2(
"http://cache.soso.com/30d/img/web/logo.gif"
, R.id.image5);
047
// loadImage3("http://www.chinatelecom.com.cn/images/logo_new.gif", R.id.image1);
048
// loadImage3("http://www.baidu.com/img/baidu_logo.gif", R.id.image2);
049
// loadImage3("http://cache.soso.com/30d/img/web/logo.gif", R.id.image3);
050
// loadImage3("http://www.baidu.com/img/baidu_logo.gif", R.id.image4);
051
// loadImage3("http://cache.soso.com/30d/img/web/logo.gif", R.id.image5);
052
053
// loadImage4("http://www.chinatelecom.com.cn/images/logo_new.gif", R.id.image1);
054
// loadImage4("http://www.baidu.com/img/baidu_logo.gif", R.id.image2);
055
// loadImage4("http://cache.soso.com/30d/img/web/logo.gif", R.id.image3);
056
// loadImage4("http://www.baidu.com/img/baidu_logo.gif", R.id.image4);
057
// loadImage4("http://cache.soso.com/30d/img/web/logo.gif", R.id.image5);
058
059
// loadImage5("http://www.chinatelecom.com.cn/images/logo_new.gif", R.id.image1);
060
// //为了测试缓存而模拟的网络延时
061
// SystemClock.sleep(2000);
062
// loadImage5("http://www.baidu.com/img/baidu_logo.gif", R.id.image2);
063
// SystemClock.sleep(2000);
064
// loadImage5("http://cache.soso.com/30d/img/web/logo.gif", R.id.image3);
065
// SystemClock.sleep(2000);
066
// loadImage5("http://www.baidu.com/img/baidu_logo.gif", R.id.image4);
067
// SystemClock.sleep(2000);
068
// loadImage5("http://cache.soso.com/30d/img/web/logo.gif", R.id.image5);
069
// SystemClock.sleep(2000);
070
// loadImage5("http://www.baidu.com/img/baidu_logo.gif", R.id.image4);
071
}
072
073
@Override
074
protected
void
onDestroy() {
075
executorService.shutdown();
076
super
.onDestroy();
077
}
078
//线程加载图像基本原理
079
private
void
loadImage(
final
String url,
final
int
id) {
080
handler.post(
new
Runnable() {
081
public
void
run() {
082
Drawable drawable =
null
;
083
try
{
084
drawable = Drawable.createFromStream(
new
URL(url).openStream(),
"image.png"
);
085
}
catch
(IOException e) {
086
}
087
((ImageView) LazyLoadImageActivity.
this
.findViewById(id)).setImageDrawable(drawable);
088
}
089
});
090
}
091
//采用handler+Thread模式实现多线程异步加载
092
private
void
loadImage2(
final
String url,
final
int
id) {
093
Thread thread =
new
Thread(){
094
@Override
095
public
void
run() {
096
Drawable drawable =
null
;
097
try
{
098
drawable = Drawable.createFromStream(
new
URL(url).openStream(),
"image.png"
);
099
}
catch
(IOException e) {
100
}
101
102
Message message= handler2.obtainMessage() ;
103
message.arg1 = id;
104
message.obj = drawable;
105
handler2.sendMessage(message);
106
}
107
};
108
thread.start();
109
thread =
null
;
110
}
111
// 引入线程池来管理多线程
112
private
void
loadImage3(
final
String url,
final
int
id) {
113
executorService.submit(
new
Runnable() {
114
public
void
run() {
115
try
{
116
final
Drawable drawable = Drawable.createFromStream(
new
URL(url).openStream(),
"image.png"
);
117
handler.post(
new
Runnable() {
118
119
public
void
run() {
120
((ImageView) LazyLoadImageActivity.
this
.findViewById(id)).setImageDrawable(drawable);
121
}
122
});
123
}
catch
(Exception e) {
124
throw
new
RuntimeException(e);
125
}
126
}
127
});
128
}
129
//引入线程池,并引入内存缓存功能,并对外部调用封装了接口,简化调用过程
130
private
void
loadImage4(
final
String url,
final
int
id) {
131
//如果缓存过就会从缓存中取出图像,ImageCallback接口中方法也不会被执行
132
Drawable cacheImage = asyncImageLoader.loadDrawable(url,
new
AsyncImageLoader.ImageCallback() {
133
//请参见实现:如果第一次加载url时下面方法会执行
134
public
void
imageLoaded(Drawable imageDrawable) {
135
((ImageView) findViewById(id)).setImageDrawable(imageDrawable);
136
}
137
});
138
if
(cacheImage!=
null
){
139
((ImageView) findViewById(id)).setImageDrawable(cacheImage);
140
}
141
}
142
143
//采用Handler+Thread+封装外部接口
144
private
void
loadImage5(
final
String url,
final
int
id) {
145
//如果缓存过就会从缓存中取出图像,ImageCallback接口中方法也不会被执行
146
Drawable cacheImage = asyncImageLoader3.loadDrawable(url,
new
AsyncImageLoader3.ImageCallback() {
147
//请参见实现:如果第一次加载url时下面方法会执行
148
public
void
imageLoaded(Drawable imageDrawable) {
149
((ImageView) findViewById(id)).setImageDrawable(imageDrawable);
150
}
151
});
152
if
(cacheImage!=
null
){
153
((ImageView) findViewById(id)).setImageDrawable(cacheImage);
154
}
155
}
156
157
158
}
xml文件大致如下:
01
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
02
03
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
04
android:layout_width
=
"fill_parent"
05
android:orientation
=
"vertical"
06
android:layout_height
=
"fill_parent"
>
07
<
ImageView
android:id
=
"@+id/image1"
android:layout_height
=
"wrap_content"
android:layout_width
=
"fill_parent"
></
ImageView
>
08
<
ImageView
android:id
=
"@+id/image2"
android:layout_height
=
"wrap_content"
android:layout_width
=
"fill_parent"
></
ImageView
>
09
<
ImageView
android:id
=
"@+id/image3"
android:layout_height
=
"wrap_content"
android:layout_width
=
"fill_parent"
></
ImageView
>
10
<
ImageView
android:id
=
"@+id/image5"
android:layout_height
=
"wrap_content"
android:layout_width
=
"fill_parent"
></
ImageView
>
11
<
ImageView
android:id
=
"@+id/image4"
android:layout_height
=
"wrap_content"
android:layout_width
=
"fill_parent"
></
ImageView
>
12
</
LinearLayout
>
转自:http://blog.csdn.net/itachi85/article/details/7589660
- Android异步加载图像(含线程池,缓存方法)
- Android异步加载图像(含线程池,缓存方法) .
- Android异步加载图像(含线程池,缓存方法)
- Android异步加载图像(含线程池,缓存方法)
- Android异步加载图像(含线程池,缓存方法)
- Android异步加载图像(含线程池,缓存方法)
- Android异步加载图像(含线程池,缓存方法)
- Android异步加载图像(含线程池,缓存方法)
- Android异步加载图像(含线程池,缓存方法)
- Android异步加载图像(含线程池,缓存方法)
- Android异步加载图像小结 (含线程池,缓存方法)
- Android异步加载图像小结(含线程池,缓存方法)[转]
- Android异步加载图像小结 (含线程池,缓存方法)
- Android异步加载图像小结 (含线程池,缓存方法)
- Android异步加载图像小结 (含线程池,缓存方法)
- Android异步加载图像小结 (含线程池,缓存方法)
- Android异步加载图像小结(含线程池,缓存方法)
- Android异步加载图像小结 (含线程池,缓存方法) .
- textarea保存原文的空格和回车
- mmap详解
- 手把手教你把Vim改装成一个IDE编程环境(图文)
- php Ajax Post 传值
- Jboss中间件安全设计方案
- Android异步加载图像(含线程池,缓存方法)
- IE, FireFox, Opera 浏览器支持CSS实现Alpha半透明的方法
- struts2保存图片
- 安装SDK遇到的问题Setup cannot be run in Program Compatibility Mode
- Linux下如何删除以~开头的文件
- 动态光源效果,光源跟着鼠标走
- FreeMaker一篇通
- 收藏js
- MM_jumpMenu弹出新窗口