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);
}
}
}
|