版权声明:本文为博主原创文章,未经博主允许不得转载。
Android中的消息处理实例与分析
摘要
本文介绍了Android中的消息处理机制,给出了Android消息处理中的几个重点类Handler、Message、MessageQueue、Looper、Runnable、Thread的详细介绍,提供了两个消息处理的实例代码,并深入分析了使用Android消息机制应该遵循的几个原则。
阅读本文的收获
在具有java基础的情况下,Android的学习比较轻松,很多人在没有深刻了解Android消息处理机制的背景下,已经能够开发出可用的app,很多人开始想学习Android消息处理机制的第一个动机是遇到了一个著名的bug“CalledFromWrongThreadException:Only the original thread that created a view hierarchy can touch its views.”。这个bug的含义即“只有创建一个view层次的线程能够更新此view”,在更多情况下,它是想说“只有主线程能够更新UI”。
本文即是来解释如何利用Android的消息机制从主线程或者子线程中更新UI或完成其他操作。你可以学到:
1. 如何使用Android的消息实现同步、异步操作;
2. 如何在主线程和子线程发送并接收消息;
3. 消息是如何得到处理的;
4. 使用Android的消息处理机制应该遵循的几个原则;
5. 两个具体的消息处理实例源代码。
阅读本文需要的技术背景
你可能需要如下技术背景才能完全理解本文的内容,如何你没有以下背景,建议先学习相关知识:
1. Java语言基础
2. Java多线程技术
3. Android开发基本知识
第一个例子:在主线程和子线程中发送消息,在主线程中处理消息
先来看一个代码,代码地址为:
http://download.csdn.net/detail/logicteamleader/8827099
本例的作用是:创建一个Handler(处理消息的类),在界面上点击按钮就会向此Handler发送消息,Handler可以处理这些消息(后面会详细解释,消息的处理其实是多个类共同合作的结果),对UI进行修改。界面上有八个按钮,从上至下其效果分别是:
1. 使用Handler的post来传递一个Runnable的实例,该实例的run方法会在按钮点击时运行;
2. 使用Handler的postDelayed(Runnable r, long delayMillis)来传递一个Runnable的实例,该实例的run方法会在一段时间delayMillis后执行;
3. 使用Handler的sendMessage方法传递一个消息,该消息在Handler的handleMessage方法中被解析执行;
4. 使用Message的sendToTarget方法向获得该Message的Handler传递一个消息,该消息在Handler的handleMessage方法中被解析执行;
第5、6、7、8个方法与上面四个方法类似,不同的是它们都是在子线程中调用的。
源代码如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 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
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
几个规则
看完代码后,在解释具体类之前,先了解几个规则:
第一, 只有创建view的线程能够更新此view;一般来说,创建UI的是Android主线程,因此只有在主线程中才能更新UI;
第二, 处理消息的类是Handler,它依附于创建自己的线程;如果在主线程中创建Handler mHandler,则向mHandler发送的消息会在主线程中被解析;如果在子线程中创建Handler sHandler,则向sHandler发送的消息会在子线程中被解析;
第三, 发送消息有三类方法,Handler的post方法,Handler的sendMessage方法,以及Message的sentToTarget方法,它们最终其实都调用了Handler的sendMessage方法;
第四, 消息的方法可以即时也可以延时,代表就是post和postDelay,以及sendMessage和sendMessageDelayed;延时发送消息可以实现很多用户需要的界面延时效果,例如最常用的SplashWindow。
第五, post类型的方法只需要实例化一个Runnable接口,且不需要重载Handler. handleMessage方法,比较简单易用;
第六, sendMessage和sentToTarget需要重载Handler. handleMessage方法,实现对不同消息的解析。
Handler
Handler是Android消息处理中最重要的一个类,不管什么编程语言或者框架,叫Handler的类一般都很重要,也都很复杂,当年的Windows句柄类更是让人一头雾水。
幸好,Android的Handler很容易理解和使用。它就是一个消息处理的目标类,其主要作用有两个:1)它安排要执行的消息和runnable在未来某个时间点执行;2)处理来自不同线程的消息并执行操作。
使用Handler要注意以下几点:
1. Handler属于创建它的线程,并与线程的消息循环关联,同时与此线程的消息队列(MessageQueue)关联。
2. Handler发送消息的方法有两类:post类和sendMessage类,用法见例子;
3. 如果使用post发送消息,则消息中包含的Runnable会在解析消息时执行;
4. 如果使用sendMessage发送消息,则需要重载Handler. handleMessage方法,实现对不同消息的解析
Message
Message是消息类,它有几个重要的属性:
public int what:消息类型
public int arg1:参数1
public int arg2:参数2
public Object obj:对象参数
以上几个参数用户可以随意定制。
值得注意的有几点:
1. Android使用消息池模式来提高消息的效率,因此一般不适用new来创建消息,而是使用obtain方法来从消息池中获取一个Message的实例;Handler类也有obtain方法;
2. Message有一个Handler作为Target,一般来说就是获取该消息的所在线程的关联Handler;因此使用sendToTarget方法发送消息时,将消息发给它的Target;
MessageQueue
MessageQueue是消息队列,一个线程最多拥有一个消息队列,这个类一般不会被程序员直接使用。它的入队方法enqueueMessage用来将一个Message加入队列,这个方法是线程安全的,因此才保证了Android的消息处理机制是线程安全的。
MessageQueue的next方法用来获取下一个Message,没有任何消息时,主线程常常在此方法处等待。
Runnable
Java的接口,它代表一个可执行的代码片段,如下所示:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
Thread
Java的线程类,大家都应该很熟悉了。
第二个例子:在子线程中创建消息处理循环
第一个例子描述了如何在多个线程中发送消息,并在主线程中统一接收和处理这些消息;第二个例子则描述如何在子线程中建立一个消息循环,并从主线程发送消息给子线程,让子线程处理这些消息。
第二个例子中有两个消息循环,两个Handler,主线程首先向子线程发送一个消息,子线程的收到消息后再向主线程发送一个消息,主线程收到消息后更新UI。
例子代码如下:
http://download.csdn.net/detail/logicteamleader/8827401
源代码如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 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
第二个例子使用了另一个重要的类Looper,它是代表Android中的消息循环处理类。
Looper
Looper被用来创建一个线程的消息循环。线程默认情况下是没有消息循环的,要创建消息循环,必须先调用Looper.prepare,然后在合适的地方调用Looper.loop,这个loop方法就开始循环处理本线程接收到的消息,直到loop循环被停止。
在大部分情况下,Looper都是和Handler一起使用,它通过Handler接收和处理消息。
使用Looper要注意以下几点:
1. Android的主线程是默认已经创建了Looper对象的,因此不能在主线程中调用Looper.prepare;
2. Looper.prepare和Looper.loop都是静态方法,调用时要注意,不要使用new来创建一个Looper;
总结
使用Android消息的方法有以下几种:
1. 使用Handler和Runnable,即时或延时发送一个消息;
2. 使用Handler和Message,即时或延时发送一个消息,需重载Handler. handleMessage方法;
需要注意的规则有以下几条:
1. 只有创建view的线程能够更新此view;一般来说,创建UI的是Android主线程,因此只有在主线程中才能更新UI;
2. 处理消息的类是Handler,它依附于创建自己的线程;如果在主线程中创建Handler mHandler,则向mHandler发送的消息会在主线程中被解析;如果在子线程中创建Handler sHandler,则向sHandler发送的消息会在子线程中被解析;
3. Looper被用来创建一个线程的消息循环,要创建消息循环,必须先调用Looper.prepare,然后在合适的地方调用Looper.loop。
具体的体会,还是要多看代码才行。
转自http://blog.csdn.net/logicteamleader/article/details/46591499