Android异步加载图像(含线程池,缓存方法)
研究了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从网络上异步加载图像,现总结如下: (1)由于android UI更新支持单一线程原则,所以从网络上取数据并更新到界面上,为了不阻塞主线程首先可能会想到以下方法. 在主线程中new ...
- android图片异步加载图片,Android 异步加载图片分析总结
研究了android从网络上异步加载图像,现总结如下: (1)由于android UI更新支持单一线程原则,所以从网络上取数据并更新到界面上,为了不阻塞主线程首先可能会想到以下方法. 在主线程中new ...
- Android:异步加载图片
我们知道Android为了不阻塞UI线程(main线程),不允许在非UI线程中进行UI操作以及网络请求等操作,为了不阻塞UI,我们往往就要进行异步加载. 我们以异步加载图片为例子,来学习一下异步加载 ...
- android异步加载图片并缓存到内存和sd卡上,Android批量图片加载经典系列——采用二级缓存、异步加载网络图片...
http://www.cnblogs.com/jerehedu/p/4560119.html 2015-06-08 09:20 by 杰瑞教育, 232 阅读, 1 评论, 收藏, 编辑一.问题描述 ...
- Android异步加载全解析之引入二级缓存
Android异步加载全解析之引入二级缓存 为啥要二级缓存 前面我们有了一级缓存,为啥还要二级缓存呢?说白了,这就和电脑是一样的,我们电脑有内存和硬盘,内存读取速度快,所以CPU直接读取内存中的数据, ...
- 异步加载js文件并执行js方法:实现异步处理网页的复杂效果
异步加载js文件并执行js方法:实现异步处理网页的复杂效果 有这么一个场景,当你的网页页面效果过多就会造成了打开页面的速度变得缓慢,长时间处于加载的状态,这样的效果通常会让用户感到不友好,通常的处理方 ...
- 演化理解 Android 异步加载图片
引用:http://www.cnblogs.com/ghj1976/archive/2011/05/06/2038738.html 下面测试使用的layout文件: 简单来说就是 LinearLayo ...
- Android异步加载
为什么要异步加载: 为了用户体验,避免卡顿 Android系统要求使用异步加载,耗时操作会阻塞UI线程 异步加载的常用的方式: 多线程/线程池 AsyncTask 以下以加载网络图片为示例 在主类之外 ...
- android 异步加载图片总结
一Handler+Runnable模式 我们先看一个并不是异步线程加载的例子,使用 Handler+Runnable模式. 这里为何不是新开线程的原因请参看这篇文章:Android Runnable ...
最新文章
- JPA时间注解(转)
- 常见工具:dp与px互转,屏幕宽度与高度获取
- 微信小程序,引用扩展组件提示“没有找到可以构建的NPM包”
- 一个关于pynoi游戏的C语言编程
- 开箱视频│ 能走!能跑!还能叠起来!金史密斯R1跑步机开箱
- 用于最优控制的简单软件
- Java实现websocket
- R语言神经网络与深度学习(一)
- ModuleNotFoundError: No module named ‘librosa‘
- zabbix (二)安装
- JAVA操作文件大全(二)
- 【AAAI会议】三位教父上演神仙打架,Hinton吐槽CNN就是个“垃圾”
- RabbitMQ 线上事故!慌的一批,脑袋一片空白……
- mysql数据库容灾方案_本地IDC机房数据库容灾解决方案
- 《新概念模拟电路》- 晶体管-西北模电王-杨建国著
- 关于一段式、两段式、三段式状态机
- 终于稳了!2020年8月程序员工资最新统计
- StarUML使用心得
- 读吴军一万小时定律误区有感
- html表格文字方向改变,excel表格怎么改变文字方向