Hanlder和message机制:

【概述】

android的Handler+Thread机制是android实现异步任务或者说实现更新UI界面最本质的方式,Handler+thread机制区别于Async Task机制的不同在于Async Task封装了Handler(因为在其源码实现中就已经获取了uiThread的Handler实现了其looper)并用线程池来实现。这两者在本质上区别不大。因为Handler+Thread是最本质的实现异步任务的方式,所以其效率肯定更高于Async Task。但是Async Task是android的改良品,代码更易读,在代码维护方面是很大的优势。

1、为何需要多线程

在日常应用中,我们通常需要处理一些“后台,用户不可见”的操作,例如说,我们需要下载一个音乐,要是你的应用必须等用户下载完成之后才可以进行别的操作,那肯定让用户非常的不爽。这时候,我们通常的做法是,让这些操作去后台执行,然后等后台执行完毕之后,再给用户弹出相应的提示信息。这时候,我们就需要使用多线程机制,然后通过创建一个新的线程来执行这些操作。

明白了,实现需求,我们就准备着手实现了。但是,经过进一步的了解,我们悲剧的发现,android中的线程机制是,只能在UI线程中和用户进行交互。当我们创建了一个新线程,执行了一些后台操作,执行完成之后,我们想要给用户弹出对话框以确认,但是却悲剧的发现,我们根本无法返回UI主线程了。(UI线程就是你当前看到的这些交互界面所属的线程)。

这时候,我们如果想要实现这些功能,我们就需要一个android为我们提供的handler和message机制。

2、解说Handler下的编程机制

我们通常在UI线程中创建一个handler,handler相当于一个处理器,它主要负责处理和绑定到该handler的线程中的message。每一个handler都必须关联一个looper,并且两者是一一对应的,注意,这点很重要哦!此外,looper负责从其内部的messageQueue中拿出一个个的message给handler进行处理。因为我们这里handler是在UI线程中实现的,所以经过这么一个handler、message机制,我们就可以回到UI线程中了。

handler:处理后台进程返回数据的工作人员。

message:后台进程返回的数据,里面可以存储bundle等数据格式

messageQueue:是线程对应looper的一部分,负责存储从后台进程中抛回的和当前handler绑定的message,是一个队列。

looper:looper相当于一个messageQueue的管理人员,它会不停的循环的遍历队列,然后将符合条件的message一个个的拿出来交给handler进行处理。

注意,handler是在UI线程中声明的,如果我们直接用类似代码执行一个线程的话,实际上并没有创建一个新的线程,因为handler已经跟默认的UI线程中的looper绑定了。

如果有兴趣的话,可以去看下Handler的默认空构造函数便知道原因了,里面直接绑定了当前UI线程的looper。

3、示例小程序:


1. public class MainActivity extends Activity implements OnClickListener {  
2. private Button btnTXT;  
3. private TextView tvTXT;  
4.       
5. private StringBuffer returnMsg;  
6.       
7. @Override  
8. public void onCreate(Bundle savedInstanceState) {  
9. super.onCreate(savedInstanceState);  
10.         setContentView(R.layout.activity_main);  
11.           
12.         btnTXT = (Button)findViewById(R.id.btnTXT);  
13.         tvTXT = (TextView)findViewById(R.id.tvTXT);  
14.           
15. this);          
16.     }  
17.   
18. @Override  
19. public void onClick(View v) {  
20. new StringBuffer();  
21.           
22. // 创建一个包含Looper的线程,这里如果没有HandlerThread的调用,会直接将后边的MyRunnable放到UI线程队列(myHandler.post(new MyRunnable()))  
23. new HandlerThread("handler_thread");  
24. // 启动自定义处理线程  
25.           
26. new MyHandler(handlerThread.getLooper());       // 将handler绑定到新线程    
27. new MyRunnable());       // 在新线程中执行任务   
28.     }  
29.       
30. /** 主线程Handler,可以与UI控件交互 */  
31. new Handler(){  
32. @Override  
33. public void handleMessage(Message msg) {  
34. if(msg.what == 0) {  
35. // 与主线程控件打交道(直接访问)  
36.             }  
37.         }  
38.     };  
39.   
40.       
41. /** 构造Hanlder,不可与UI控件直接交互 */  
42. private MyHandler myHandler = null;  
43. private class MyHandler extends Handler{  
44. /** 
45.          * 使用默认的构造函数,会将handler绑定当前UI线程的looper。 
46.          * 如果想使用多线程这里是不能使用默认的构造方法的。 
47.          */    
48. public MyHandler(){  
49. super();  
50.         }  
51.           
52. /** 构造函数,自定义looper */  
53. public MyHandler(Looper looper) {  
54. super(looper);  
55.         }  
56.           
57. // 处理具体的message消息,继承自父类的方法  
58. @Override  
59. public void handleMessage(Message msg) {  
60. int what = msg.what;      
61. // 提取bundle中的信息  
62. "name");  
63. "sex");  
64. boolean marry = bundle.getBoolean("marray");  
65. int age = bundle.getInt("age");  
66.               
67. new StringBuffer();       // 拼接bundle信息  
68. "what = ").append(what).append("\n\n");  
69. "name = ").append(name).append("\n");  
70. "sex = ").append(sex).append("\n");  
71. "marry = ").append(marry).append("\n");  
72. "age = ").append(age).append("\n\n");  
73. "");  
74.               
75. // 保存要显示的结果  
76. 0);        // 向主线程mainHanlder发送消息,与UI控件交互显示结果  
77.               
78. super.handleMessage(msg);  
79.         }  
80.     }  
81.       
82.       
83. // 构造Runnable,处理后台业务逻辑,如下载  
84. private class MyRunnable implements Runnable{  
85. @Override  
86. public void run() {  
87. try {  
88. // 捕获myHandler消息  
89.                   
90. 10;  
91. new Bundle();               // 封装bundle信息  
92. "name", "yanggang");  
93. "sex", "pure boy");  
94. "marry", false);  
95. "age", 18);  
96.                 msg.obj = bundle;  
97.                   
98. long thID = Thread.currentThread().getId();  
99. " : send msg start...").append("\n");  
100. // 向myHandler发送消息  
101.   
102. 3000);  
103. catch (Exception e) {  
104. "", "Runnable send msg error...");  
105.                 e.printStackTrace();  
106.             }  
107.         }  
108.     }  
109. }



运行结果:

Android handler在子线程安全吗 android handlerthread机制_handler