研究了android从网络上异步加载图像:
(1)由于android UI更新支持单一线程原则,所以从网络上取数据并更新到界面上,为了不阻塞主线程首先可能会想到以下方法。
在主线程中new 一个Handler对象,加载图像方法如下所示
1
2
3
4
5
6
7
8
9
10
11
12
|
private void loadImage( final String url, final int id) {
handler.post( new Runnable() {
public void run() {
Drawable drawable = null ;
try {
drawable = Drawable.createFromStream( new URL(url).openStream(), "image.png" );
} catch (IOException e) {
}
((ImageView) LazyLoadImageActivity. this .findViewById(id)).setImageDrawable(drawable);
}
});
}
|
上面这个方法缺点很显然,经测试,如果要加载多个图片,这并不能实现异步加载,而是等到所有的图片都加载完才一起显示,因为它们都运行在一个线程中。
然后,我们可以简单改进下,将Handler+Runnable模式改为Handler+Thread+Message模式不就能实现同时开启多个线程吗?
(2)在主线程中new 一个Handler对象,代码如下:
1
2
3
4
5
6
|
final Handler handler2= new Handler(){
@Override
public void handleMessage(Message msg) {
((ImageView) LazyLoadImageActivity. this .findViewById(msg.arg1)).setImageDrawable((Drawable)msg.obj);
}
};
|
对应加载图像代码如下:对应加载图像代码如下:对应加载图像代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// 引入线程池来管理多线程 private void loadImage3( final String url, final int id) {
executorService.submit( new Runnable() {
public void run() {
try {
final Drawable drawable = Drawable.createFromStream( new URL(url).openStream(), "image.png" );
handler.post( new Runnable() {
public void run() {
((ImageView) LazyLoadImageActivity. this .findViewById(id)).setImageDrawable(drawable);
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
}
|
(4)为了更方便使用我们可以将异步加载图像方法封装一个类,对外界只暴露一个方法即可,考虑到效率问题我们可以引入内存缓存机制,做法是
建立一个HashMap,其键(key)为加载图像url,其值(value)是图像对象Drawable。先看一下我们封装的类
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
|
public class AsyncImageLoader3 {
//为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动)
public Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();
private ExecutorService executorService = Executors.newFixedThreadPool( 5 ); //固定五个线程来执行任务
private final Handler handler= new Handler();
/**
*
* @param imageUrl 图像url地址
* @param callback 回调接口
* @return 返回内存中缓存的图像,第一次加载返回null
*/
public Drawable loadDrawable( final String imageUrl, final ImageCallback callback) {
//如果缓存过就从缓存中取出数据
if (imageCache.containsKey(imageUrl)) {
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
if (softReference.get() != null ) {
return softReference.get();
}
}
//缓存中没有图像,则从网络上取出数据,并将取出的数据缓存到内存中
executorService.submit( new Runnable() {
public void run() {
try {
final Drawable drawable = Drawable.createFromStream( new URL(imageUrl).openStream(), "image.png" );
imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
handler.post( new Runnable() {
public void run() {
callback.imageLoaded(drawable);
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
return null ;
}
//从网络上取数据方法
protected Drawable loadImageFromUrl(String imageUrl) {
try {
return Drawable.createFromStream( new URL(imageUrl).openStream(), "image.png" );
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//对外界开放的回调接口
public interface ImageCallback {
//注意 此方法是用来设置目标对象的图像资源
public void imageLoaded(Drawable imageDrawable);
}
} |
这样封装好后使用起来就方便多了。在主线程中首先要引入AsyncImageLoader3 对象,然后直接调用其loadDrawable方法即可,需要注意的是ImageCallback接口的imageLoaded方法是唯一可以把加载的图像设置到目标ImageView或其相关的组件上。
在主线程调用代码:
先实例化对象 private AsyncImageLoader3 asyncImageLoader3 = new AsyncImageLoader3();
调用异步加载方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//引入线程池,并引入内存缓存功能,并对外部调用封装了接口,简化调用过程 private void loadImage4( final String url, final int id) {
//如果缓存过就会从缓存中取出图像,ImageCallback接口中方法也不会被执行
Drawable cacheImage = asyncImageLoader.loadDrawable(url, new AsyncImageLoader.ImageCallback() {
//请参见实现:如果第一次加载url时下面方法会执行
public void imageLoaded(Drawable imageDrawable) {
((ImageView) findViewById(id)).setImageDrawable(imageDrawable);
}
});
if (cacheImage!= null ){
((ImageView) findViewById(id)).setImageDrawable(cacheImage);
}
}
|
5)同理,下面也给出采用Thread+Handler+MessageQueue+内存缓存代码,原则同(4),只是把线程池换成了Thread+Handler+MessageQueue模式而已。代码如下:5)同理,下面也给出采用Thread+Handler+MessageQueue+内存缓存代码,原则同(4),只是把线程池换成了Thread+Handler+MessageQueue模式而已。代码如下:
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
|
public class AsyncImageLoader {
//为了加快速度,加入了缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动)
private Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();
/**
*
* @param imageUrl 图像url地址
* @param callback 回调接口
* @return 返回内存中缓存的图像,第一次加载返回null
*/
public Drawable loadDrawable( final String imageUrl, final ImageCallback callback) {
//如果缓存过就从缓存中取出数据
if (imageCache.containsKey(imageUrl)) {
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
if (softReference.get() != null ) {
return softReference.get();
}
}
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
callback.imageLoaded((Drawable) msg.obj);
}
};
new Thread() {
public void run() {
Drawable drawable = loadImageFromUrl(imageUrl);
imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
handler.sendMessage(handler.obtainMessage( 0 , drawable));
}
}.start();
/*
下面注释的这段代码是Handler的一种代替方法
*/
// new AsyncTask() { // @Override // protected Drawable doInBackground(Object... objects) { // Drawable drawable = loadImageFromUrl(imageUrl); // imageCache.put(imageUrl, new SoftReference<Drawable>(drawable)); // return drawable; // } // // @Override // protected void onPostExecute(Object o) { // callback.imageLoaded((Drawable) o); // } // }.execute(); return null ;
}
protected Drawable loadImageFromUrl(String imageUrl) {
try {
return Drawable.createFromStream( new URL(imageUrl).openStream(), "src" );
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//对外界开放的回调接口
public interface ImageCallback {
public void imageLoaded(Drawable imageDrawable);
}
} |
至此,异步加载就介绍完了,下面给出的代码为测试用的完整代码:
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
package com.bshark.supertelphone.activity;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;
import com.bshark.supertelphone.R;
import com.bshark.supertelphone.ui.adapter.util.AsyncImageLoader;
import com.bshark.supertelphone.ui.adapter.util.AsyncImageLoader3;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class LazyLoadImageActivity extends Activity {
final Handler handler= new Handler();
final Handler handler2= new Handler(){
@Override
public void handleMessage(Message msg) {
((ImageView) LazyLoadImageActivity. this .findViewById(msg.arg1)).setImageDrawable((Drawable)msg.obj);
}
};
private ExecutorService executorService = Executors.newFixedThreadPool( 5 ); //固定五个线程来执行任务
private AsyncImageLoader asyncImageLoader = new AsyncImageLoader();
private AsyncImageLoader3 asyncImageLoader3 = new AsyncImageLoader3();
@Override public void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.main);
// loadImage("http://www.chinatelecom.com.cn/images/logo_new.gif", R.id.image1); // loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.image2); // loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.image3); // loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.image4); // loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.image5); loadImage2( "http://www.chinatelecom.com.cn/images/logo_new.gif" , R.id.image1);
loadImage2( "http://www.baidu.com/img/baidu_logo.gif" , R.id.image2);
loadImage2( "http://cache.soso.com/30d/img/web/logo.gif" , R.id.image3);
loadImage2( "http://www.baidu.com/img/baidu_logo.gif" , R.id.image4);
loadImage2( "http://cache.soso.com/30d/img/web/logo.gif" , R.id.image5);
// loadImage3("http://www.chinatelecom.com.cn/images/logo_new.gif", R.id.image1); // loadImage3("http://www.baidu.com/img/baidu_logo.gif", R.id.image2); // loadImage3("http://cache.soso.com/30d/img/web/logo.gif", R.id.image3); // loadImage3("http://www.baidu.com/img/baidu_logo.gif", R.id.image4); // loadImage3("http://cache.soso.com/30d/img/web/logo.gif", R.id.image5); // loadImage4("http://www.chinatelecom.com.cn/images/logo_new.gif", R.id.image1); // loadImage4("http://www.baidu.com/img/baidu_logo.gif", R.id.image2); // loadImage4("http://cache.soso.com/30d/img/web/logo.gif", R.id.image3); // loadImage4("http://www.baidu.com/img/baidu_logo.gif", R.id.image4); // loadImage4("http://cache.soso.com/30d/img/web/logo.gif", R.id.image5); // loadImage5("http://www.chinatelecom.com.cn/images/logo_new.gif", R.id.image1); // //为了测试缓存而模拟的网络延时 // SystemClock.sleep(2000); // loadImage5("http://www.baidu.com/img/baidu_logo.gif", R.id.image2); // SystemClock.sleep(2000); // loadImage5("http://cache.soso.com/30d/img/web/logo.gif", R.id.image3); // SystemClock.sleep(2000); // loadImage5("http://www.baidu.com/img/baidu_logo.gif", R.id.image4); // SystemClock.sleep(2000); // loadImage5("http://cache.soso.com/30d/img/web/logo.gif", R.id.image5); // SystemClock.sleep(2000); // loadImage5("http://www.baidu.com/img/baidu_logo.gif", R.id.image4); } @Override protected void onDestroy() {
executorService.shutdown();
super .onDestroy();
} //线程加载图像基本原理
private void loadImage( final String url, final int id) {
handler.post( new Runnable() {
public void run() {
Drawable drawable = null ;
try {
drawable = Drawable.createFromStream( new URL(url).openStream(), "image.png" );
} catch (IOException e) {
}
((ImageView) LazyLoadImageActivity. this .findViewById(id)).setImageDrawable(drawable);
}
});
}
//采用handler+Thread模式实现多线程异步加载
private void loadImage2( final String url, final int id) {
Thread thread = new Thread(){
@Override
public void run() {
Drawable drawable = null ;
try {
drawable = Drawable.createFromStream( new URL(url).openStream(), "image.png" );
} catch (IOException e) {
}
Message message= handler2.obtainMessage() ;
message.arg1 = id;
message.obj = drawable;
handler2.sendMessage(message);
}
};
thread.start();
thread = null ;
}
// 引入线程池来管理多线程
private void loadImage3( final String url, final int id) {
executorService.submit( new Runnable() {
public void run() {
try {
final Drawable drawable = Drawable.createFromStream( new URL(url).openStream(), "image.png" );
handler.post( new Runnable() {
public void run() {
((ImageView) LazyLoadImageActivity. this .findViewById(id)).setImageDrawable(drawable);
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
}
//引入线程池,并引入内存缓存功能,并对外部调用封装了接口,简化调用过程
private void loadImage4( final String url, final int id) {
//如果缓存过就会从缓存中取出图像,ImageCallback接口中方法也不会被执行
Drawable cacheImage = asyncImageLoader.loadDrawable(url, new AsyncImageLoader.ImageCallback() {
//请参见实现:如果第一次加载url时下面方法会执行
public void imageLoaded(Drawable imageDrawable) {
((ImageView) findViewById(id)).setImageDrawable(imageDrawable);
}
});
if (cacheImage!= null ){
((ImageView) findViewById(id)).setImageDrawable(cacheImage);
}
}
//采用Handler+Thread+封装外部接口
private void loadImage5( final String url, final int id) {
//如果缓存过就会从缓存中取出图像,ImageCallback接口中方法也不会被执行
Drawable cacheImage = asyncImageLoader3.loadDrawable(url, new AsyncImageLoader3.ImageCallback() {
//请参见实现:如果第一次加载url时下面方法会执行
public void imageLoaded(Drawable imageDrawable) {
((ImageView) findViewById(id)).setImageDrawable(imageDrawable);
}
});
if (cacheImage!= null ){
((ImageView) findViewById(id)).setImageDrawable(cacheImage);
}
}
} |
xml文件大致如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
<? xml version = "1.0" encoding = "utf-8" ?>
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:layout_width = "fill_parent"
android:orientation = "vertical"
android:layout_height = "fill_parent" >
< ImageView android:id = "@+id/image1" android:layout_height = "wrap_content" android:layout_width = "fill_parent" ></ ImageView >
< ImageView android:id = "@+id/image2" android:layout_height = "wrap_content" android:layout_width = "fill_parent" ></ ImageView >
< ImageView android:id = "@+id/image3" android:layout_height = "wrap_content" android:layout_width = "fill_parent" ></ ImageView >
< ImageView android:id = "@+id/image5" android:layout_height = "wrap_content" android:layout_width = "fill_parent" ></ ImageView >
< ImageView android:id = "@+id/image4" android:layout_height = "wrap_content" android:layout_width = "fill_parent" ></ ImageView >
</ LinearLayout >
|
转自:http://blog.csdn.net/itachi85/article/details/7589660
相关推荐
在Android应用开发中,图像加载是一个常见的...以上就是关于“Android异步加载图像小结(含线程池,缓存方法)”的主要知识点。在实际应用中,开发者应结合项目需求,合理选择和优化这些技术,以提供流畅的用户体验。
本资料包“Android异步加载图像小结(含线程池,缓存方法)”正是针对这一主题进行深入探讨的项目源码集合,适合Android开发者学习和参考。 首先,我们要理解异步加载图像的基本原理。在Android中,通常会使用...
Android项目异步加载图像小结 (含线程池,缓存方法) 本资源为一份关于Android项目中异步加载图像的详细文档,包含了线程池和缓存方法的应用。文档旨在帮助开发者解决在Android应用中高效加载大量图像的问题,提高...
Android异步加载图像小结 (含线程池,缓存方法)
"Android异步加载图像小结(含线程池,缓存方法)"这个文档详细讲解了如何在Android环境中高效、异步地加载图片,同时利用线程池和缓存策略优化性能。以下是对这些知识点的详细说明: 1. **异步加载**: - 异步...
这个压缩包包含了Android异步加载图像的详细总结,包括线程池的使用和缓存策略的实现。无论你是使用Android Studio还是IntelliJ IDEA,都可以导入项目进行学习和实践。对于Eclipse用户,虽然官方已不再支持,但也...