Handler+ExecutorService线程池+MessageQueue模式+缓存模式.docx

上传人:b****7 文档编号:8830191 上传时间:2023-02-02 格式:DOCX 页数:16 大小:19.47KB
下载 相关 举报
Handler+ExecutorService线程池+MessageQueue模式+缓存模式.docx_第1页
第1页 / 共16页
Handler+ExecutorService线程池+MessageQueue模式+缓存模式.docx_第2页
第2页 / 共16页
Handler+ExecutorService线程池+MessageQueue模式+缓存模式.docx_第3页
第3页 / 共16页
Handler+ExecutorService线程池+MessageQueue模式+缓存模式.docx_第4页
第4页 / 共16页
Handler+ExecutorService线程池+MessageQueue模式+缓存模式.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

Handler+ExecutorService线程池+MessageQueue模式+缓存模式.docx

《Handler+ExecutorService线程池+MessageQueue模式+缓存模式.docx》由会员分享,可在线阅读,更多相关《Handler+ExecutorService线程池+MessageQueue模式+缓存模式.docx(16页珍藏版)》请在冰豆网上搜索。

Handler+ExecutorService线程池+MessageQueue模式+缓存模式.docx

Handler+ExecutorService线程池+MessageQueue模式+缓存模式

android线程池的理解,晚上在家无事预习了一下android异步加载的例子,也学习到了一个很重要的东东那就是线程池+缓存下面看他们的理解。

[size=1.8em]Handler+Runnable模式

我们先看一个并不是异步线程加载的例子,使用Handler+Runnable模式。

这里为何不是新开线程的原因请参看这篇文章:

AndroidRunnable运行在那个线程这里的代码其实是在UI主线程中下载图片的,而不是新开线程。

我们运行下面代码时,会发现他其实是阻塞了整个界面的显示,需要所有图片都加载完成后,才能显示界面。

?

代码片段,双击复制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

packageghj1976.AndroidTest;

importjava.io.IOException;

.URL;

importandroid.app.Activity;

importandroid.graphics.drawable.Drawable;

importandroid.os.Bundle;

importandroid.os.Handler;

importandroid.os.SystemClock;

importandroid.util.Log;

importandroid.widget.ImageView;

publicclassMainActivityextendsActivity{

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

loadImage("R.id.imageView1);

loadImage(",

R.id.imageView2);

loadImage("R.id.imageView3);

loadImage("

R.id.imageView4);

loadImage("

R.id.imageView5);

}

privateHandlerhandler=newHandler();

privatevoidloadImage(finalStringurl,finalintid){

handler.post(newRunnable(){

publicvoidrun(){

Drawabledrawable=null;

try{

drawable=Drawable.createFromStream(

newURL(url).openStream(),"image.gif");

}catch(IOExceptione){

Log.d("test",e.getMessage());

}

if(drawable==null){

Log.d("test","nulldrawable");

}else{

Log.d("test","notnulldrawable");

}

//为了测试缓存而模拟的网络延时

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

packageghj1976.AndroidTest;

importjava.io.IOException;

.URL;

importandroid.app.Activity;

importandroid.graphics.drawable.Drawable;

importandroid.os.Bundle;

importandroid.os.Handler;

importandroid.os.Message;

importandroid.os.SystemClock;

importandroid.util.Log;

importandroid.widget.ImageView;

publicclassMainActivityextendsActivity{

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

loadImage2("R.id.imageView1);

loadImage2("

R.id.imageView2);

loadImage2("R.id.imageView3);

loadImage2("

R.id.imageView4);

loadImage2("

R.id.imageView5);

}

finalHandlerhandler2=newHandler(){

@Override

publicvoidhandleMessage(Messagemsg){

((ImageView)MainActivity.this.findViewById(msg.arg1))

.setImageDrawable((Drawable)msg.obj);

}

};

//采用handler+Thread模式实现多线程异步加载

privatevoidloadImage2(finalStringurl,finalintid){

Threadthread=newThread(){

@Override

publicvoidrun(){

Drawabledrawable=null;

try{

drawable=Drawable.createFromStream(

newURL(url).openStream(),"image.png");

}catch(IOExceptione){

Log.d("test",e.getMessage());

}

//模拟网络延时

SystemClock.sleep(2000);

Messagemessage=handler2.obtainMessage();

message.arg1=id;

message.obj=drawable;

handler2.sendMessage(message);

}

};

thread.start();

thread=null;

}

}

这时候我们可以看到实现了异步加载,界面打开时,五个ImageView都是没有图的,然后在各自线程下载完后才把图自动更新上去。

Handler+ExecutorService(线程池)+MessageQueue模式

能开线程的个数毕竟是有限的,我们总不能开很多线程,对于手机更是如此。

这个例子是使用线程池。

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

packageghj1976.AndroidTest;

importjava.io.IOException;

.URL;

importjava.util.concurrent.ExecutorService;

importjava.util.concurrent.Executors;

importandroid.app.Activity;

importandroid.graphics.drawable.Drawable;

importandroid.os.Bundle;

importandroid.os.Handler;

importandroid.os.Message;

importandroid.os.SystemClock;

importandroid.util.Log;

importandroid.widget.ImageView;

publicclassMainActivityextendsActivity{

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

loadImage3("R.id.imageView1);

loadImage3("

R.id.imageView2);

loadImage3("

R.id.imageView3);

loadImage3("

R.id.imageView4);

loadImage3("

R.id.imageView5);

}

privateHandlerhandler=newHandler();

privateExecutorServiceexecutorService=Executors.newFixedThreadPool(5);

//引入线程池来管理多线程

privatevoidloadImage3(finalStringurl,finalintid){

executorService.submit(newRunnable(){

publicvoidrun(){

try{

finalDrawabledrawable=Drawable.createFromStream(

newURL(url).openStream(),"image.png");

//模拟网络延时

SystemClock.sleep(2000);

handler.post(newRunnable(){

publicvoidrun(){

((ImageView)MainActivity.this.findViewById(id))

.setImageDrawable(drawable);

}

});

}catch(Exceptione){

thrownewRuntimeException(e);

}

}

});

}

}

这里我们象第一步一样使用了handler.post(newRunnable(){更新前段显示当然是在UI主线程,我们还有executorService.submit(newRunnable(){来确保下载是在线程池的线程中。

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

packageghj1976.AndroidTest;

importjava.lang.ref.SoftReference;

.URL;

importjava.util.HashMap;

importjava.util.Map;

importjava.util.concurrent.ExecutorService;

importjava.util.concurrent.Executors;

importandroid.graphics.drawable.Drawable;

importandroid.os.Handler;

importandroid.os.SystemClock;

publicclassAsyncImageLoader3{

//为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动)

publicMap>imageCache=newHashMap>();

privateExecutorServiceexecutorService=Executors.newFixedThreadPool(5);//固定五个线程来执行任务

privatefinalHandlerhandler=newHandler();

/**

*

*@paramimageUrl

*图像url地址

*@paramcallback

*回调接口

*@return返回内存中缓存的图像,第一次加载返回null

*/

publicDrawableloadDrawable(finalStringimageUrl,

finalImageCallbackcallback){

//如果缓存过就从缓存中取出数据

if(imageCache.containsKey(imageUrl)){

SoftReferencesoftReference=imageCache.get(imageUrl);

if(softReference.get()!

=null){

returnsoftReference.get();

}

}

//缓存中没有图像,则从网络上取出数据,并将取出的数据缓存到内存中

executorService.submit(newRunnable(){

publicvoidrun(){

try{

finalDrawabledrawable=loadImageFromUrl(imageUrl);

imageCache.put(imageUrl,newSoftReference

drawable));

handler.post(newRunnable(){

publicvoidrun(){

callback.imageLoaded(drawable);

}

});

}catch(Exceptione){

thrownewRuntimeException(e);

}

}

});

returnnull;

}

//从网络上取数据方法

protectedDrawableloadImageFromUrl(StringimageUrl){

try{

//测试时,模拟网络延时,实际时这行代码不能有

SystemClock.sleep(2000);

returnDrawable.createFromStream(newURL(imageUrl).openStream(),

"image.png");

}catch(Exceptione){

thrownewRuntimeException(e);

}

}

//对外界开放的回调接口

publicinterfaceImageCallback{

//注意此方法是用来设置目标对象的图像资源

publicvoidimageLoaded(DrawableimageDrawable);

}

}

说明:

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

packageghj1976.AndroidTest;

importandroid.app.Activity;

importandroid.graphics.drawable.Drawable;

importandroid.os.Bundle;

importandroid.widget.ImageView;

publicclassMainActivityextendsActivity{

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

loadImage4("R.id.imageView1);

loadImage4("

R.id.imageView2);

loadImage4("http:

//cache.soso

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 农学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1