android线程池的理解,晚上在家无事 预习了一下android异步加载的例子,也学习到了一个很重要的东东 那就是线程池+缓存 下面看他们的理解。
[size=1.8em]Handler+Runnable模式php
咱们先看一个并非异步线程加载的例子,使用 Handler+Runnable模式。java
这里为什么不是新开线程的缘由请参看这篇文章:Android Runnable 运行在那个线程 这里的代码实际上是在UI 主线程中下载图片的,而不是新开线程。android
咱们运行下面代码时,会发现他实际上是阻塞了整个界面的显示,须要全部图片都加载完成后,才能显示界面。web
01
02
03
04
05
06
07
08
09
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
|
package
ghj1976.AndroidTest;
import
java.io.IOException;
import
java.net.URL;
import
android.app.Activity;
import
android.graphics.drawable.Drawable;
import
android.os.Bundle;
import
android.os.Handler;
import
android.os.SystemClock;
import
android.util.Log;
import
android.widget.ImageView;
public
class
MainActivity
extends
Activity {
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
loadImage(
"http://www.baidu.com/img/baidu_logo.gif"
, R.id.imageView1);
loadImage(<div style=
"width: 100px; height: 100px;background: url(static/image/common/loading.gif) no-repeat center center;"
></div><img id=
"\"aimg_LOPt3\""
onclick=
"\"zoom(this,"
this
.src,=
""
0
,=
""
0
)\
"="
" class="
\"zoom\"
" file="
\"http:
//www.chinatelecom.com.cn/images/logo_new.gif\"" onmouseover="\"img_onmouseoverfunc(this)\"" lazyloadthumb="\"1\"" border="\"0\"" alt="\"\"" src="\"http://www.chinatelecom.com.cn/images/logo_new.gif\"" lazyloaded="true" style="height: 1px; width: 1px;">",
R.id.imageView2);
loadImage("http:
//cache.soso.com/30d/img/web/logo.gif, R.id.imageView3);
loadImage(
"http://csdnimg.cn/www/images/csdnindex_logo.gif"
,
R.id.imageView4);
loadImage(
"http://images.cnblogs.com/logo_small.gif"
,
R.id.imageView5);
}
private
Handler handler =
new
Handler();
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.gif"
);
}
catch
(IOException e) {
Log.d(
"test"
, e.getMessage());
}
if
(drawable ==
null
) {
Log.d(
"test"
,
"null drawable"
);
}
else
{
Log.d(
"test"
,
"not null drawable"
);
}
// 为了测试缓存而模拟的网络延时
SystemClock.sleep(
2000
);
((ImageView) MainActivity.
this
.findViewById(id))
.setImageDrawable(drawable);
}
});
}
}
|
Handler+Thread+Message模式缓存
这种模式使用了线程,因此能够看到异步加载的效果。网络
核心代码:多线程
01
02
03
04
05
06
07
08
09
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
|
package
ghj1976.AndroidTest;
import
java.io.IOException;
import
java.net.URL;
import
android.app.Activity;
import
android.graphics.drawable.Drawable;
import
android.os.Bundle;
import
android.os.Handler;
import
android.os.Message;
import
android.os.SystemClock;
import
android.util.Log;
import
android.widget.ImageView;
public
class
MainActivity
extends
Activity {
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
loadImage2(
"http://www.baidu.com/img/baidu_logo.gif"
, R.id.imageView1);
loadImage2(
"http://www.chinatelecom.com.cn/images/logo_new.gif"
,
R.id.imageView2);
loadImage2(
"http://cache.soso.com/30d/img/web/logo.gif"
, R.id.imageView3);
loadImage2(
"http://csdnimg.cn/www/images/csdnindex_logo.gif"
,
R.id.imageView4);
loadImage2(
"http://images.cnblogs.com/logo_small.gif"
,
R.id.imageView5);
}
final
Handler handler2 =
new
Handler() {
@Override
public
void
handleMessage(Message msg) {
((ImageView) MainActivity.
this
.findViewById(msg.arg1))
.setImageDrawable((Drawable) msg.obj);
}
};
// 采用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) {
Log.d(
"test"
, e.getMessage());
}
// 模拟网络延时
SystemClock.sleep(
2000
);
Message message = handler2.obtainMessage();
message.arg1 = id;
message.obj = drawable;
handler2.sendMessage(message);
}
};
thread.start();
thread =
null
;
}
}
|
这时候咱们能够看到实现了异步加载, 界面打开时,五个ImageView都是没有图的,而后在各自线程下载完后才把图自动更新上去。app
Handler+ExecutorService(线程池)+MessageQueue模式异步
能开线程的个数毕竟是有限的,咱们总不能开不少线程,对于手机更是如此。async
这个例子是使用线程池。Android拥有与Java相同的ExecutorService实现,咱们就来用它。
线程池的基本思想仍是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样能够避免反复建立线程对象所带来的性能开销,节省了系统的资源。
线程池的信息能够参看这篇文章:Java&Android的线程池-ExecutorService 下面的演示例子是建立一个可重用固定线程数的线程池。
核心代码
01
02
03
04
05
06
07
08
09
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
|
package
ghj1976.AndroidTest;
import
java.io.IOException;
import
java.net.URL;
import
java.util.concurrent.ExecutorService;
import
java.util.concurrent.Executors;
import
android.app.Activity;
import
android.graphics.drawable.Drawable;
import
android.os.Bundle;
import
android.os.Handler;
import
android.os.Message;
import
android.os.SystemClock;
import
android.util.Log;
import
android.widget.ImageView;
public
class
MainActivity
extends
Activity {
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
loadImage3(
"http://www.baidu.com/img/baidu_logo.gif"
, R.id.imageView1);
loadImage3(
"http://www.chinatelecom.com.cn/images/logo_new.gif"
,
R.id.imageView2);
loadImage3(
"http://cache.soso.com/30d/img/web/logo.gif"
,
R.id.imageView3);
loadImage3(
"http://csdnimg.cn/www/images/csdnindex_logo.gif"
,
R.id.imageView4);
loadImage3(
"http://images.cnblogs.com/logo_small.gif"
,
R.id.imageView5);
}
private
Handler handler =
new
Handler();
private
ExecutorService executorService = Executors.newFixedThreadPool(
5
);
// 引入线程池来管理多线程
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"
);
// 模拟网络延时
SystemClock.sleep(
2000
);
handler.post(
new
Runnable() {
public
void
run() {
((ImageView) MainActivity.
this
.findViewById(id))
.setImageDrawable(drawable);
}
});
}
catch
(Exception e) {
throw
new
RuntimeException(e);
}
}
});
}
}
|
这里咱们象第一步同样使用了 handler.post(new Runnable() { 更新前段显示固然是在UI主线程,咱们还有 executorService.submit(new Runnable() { 来确保下载是在线程池的线程中。
Handler+ExecutorService(线程池)+MessageQueue+缓存模式
下面比起前一个作了几个改造:
封装的类:
01
02
03
04
05
06
07
08
09
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
|
package
ghj1976.AndroidTest;
import
java.lang.ref.SoftReference;
import
java.net.URL;
import
java.util.HashMap;
import
java.util.Map;
import
java.util.concurrent.ExecutorService;
import
java.util.concurrent.Executors;
import
android.graphics.drawable.Drawable;
import
android.os.Handler;
import
android.os.SystemClock;
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
* 回调接口
* <a href="\"http://www.eoeandroid.com/home.php?mod=space&uid=7300\"" target="\"_blank\"">@return</a> 返回内存中缓存的图像,第一次加载返回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 = loadImageFromUrl(imageUrl);
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
{
// 测试时,模拟网络延时,实际时这行代码不能有
SystemClock.sleep(
2000
);
return
Drawable.createFromStream(
new
URL(imageUrl).openStream(),
"image.png"
);
}
catch
(Exception e) {
throw
new
RuntimeException(e);
}
}
// 对外界开放的回调接口
public
interface
ImageCallback {
// 注意 此方法是用来设置目标对象的图像资源
public
void
imageLoaded(Drawable imageDrawable);
}
}
|
说明:
final参数是指当函数参数为final类型时,你能够读取使用该参数,可是没法改变该参数的值。参看:Java关键字final、static使用总结
这里使用SoftReference 是为了解决内存不足的错误(OutOfMemoryError)的,更详细的能够参看:内存优化的两个类:SoftReference 和 WeakReference
前段调用:
01
02
03
04
05
06
07
08
09
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
|
package
ghj1976.AndroidTest;
import
android.app.Activity;
import
android.graphics.drawable.Drawable;
import
android.os.Bundle;
import
android.widget.ImageView;
public
class
MainActivity
extends
Activity {
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
loadImage4(
"http://www.baidu.com/img/baidu_logo.gif"
, R.id.imageView1);
loadImage4(
"http://www.chinatelecom.com.cn/images/logo_new.gif"
,
R.id.imageView2);
loadImage4(
"http://cache.soso.com/30d/img/web/logo.gif"
,
R.id.imageView3);
loadImage4(
"http://csdnimg.cn/www/images/csdnindex_logo.gif"
,
R.id.imageView4);
loadImage4(
"http://images.cnblogs.com/logo_small.gif"
,
R.id.imageView5);
}
private
AsyncImageLoader3 asyncImageLoader3 =
new
AsyncImageLoader3();
// 引入线程池,并引入内存缓存功能,并对外部调用封装了接口,简化调用过程
private
void
loadImage4(
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);
}
}
}
|