转自:http://www.jb51.net/article/81943.htm
在 Android 中,只有主线程才能操作 UI,但是主线程不能进行耗时操作,否则会阻塞线程,产生 ANR 异常,所以常常把耗时操作放到其它子线程进行。如果在子线程中需要更新 UI,一般是通过 Handler 发送消息,主线程接受消息并且进行相应的逻辑处理。除了直接使用 Handler,还可以通过 View 的 post 方法以及 Activity 的 runOnUiThread 方法来更新 UI,它们内部也是利用了 Handler 。在上一篇文章 Android AsyncTask源码分析 中也讲到,其内部使用了 Handler 把任务的处理结果传回 UI 线程。
本文深入分析 Android 的消息处理机制,了解 Handler 的工作原理。
Handler
先通过一个例子看一下 Handler 的用法。
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
|
public
class
MainActivity
extends
AppCompatActivity {
private
static
final
int
MESSAGE_TEXT_VIEW =
0
;
private
TextView mTextView;
private
Handler mHandler =
new
Handler() {
@Override
public
void
handleMessage(Message msg) {
switch
(msg.what) {
case
MESSAGE_TEXT_VIEW:
mTextView.setText(
"UI成功更新"
);
default
:
super
.handleMessage(msg);
}
}
};
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mTextView = (TextView) findViewById(R.id.text_view);
new
Thread(
new
Runnable() {
@Override
public
void
run() {
try
{
Thread.sleep(
3000
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
mHandler.obtainMessage(MESSAGE_TEXT_VIEW).sendToTarget();
}
}).start();
}
}
|
上面的代码先是新建了一个 Handler的实例,并且重写了 handleMessage 方法,在这个方法里,便是根据接受到的消息的类型进行相应的 UI 更新。那么看一下 Handler的构造方法的源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public
Handler(Callback callback,
boolean
async) {
if
(FIND_POTENTIAL_LEAKS) {
final
Class
extends
Handler> klass = getClass();
if
((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) ==
0
) {
Log.w(TAG,
"The following Handler class should be static or leaks might occur: "
+
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if
(mLooper ==
null
) {
throw
new
RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()"
);
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
|
在构造方法中,通过调用 Looper.myLooper() 获得了 Looper 对象。如果 mLooper 为空,那么会抛出异常:"Can't create handler inside thread that has not called Looper.prepare()",意思是:不能在未调用 Looper.prepare() 的线程创建 handler。上面的例子并没有调用这个方法,但是却没有抛出异常。其实是因为主线程在启动的时候已经帮我们调用过了,所以可以直接创建 Handler 。如果是在其它子线程,直接创建 Handler 是会导致应用崩溃的。
在得到 Handler 之后,又获取了它的内部变量 mQueue, 这是 MessageQueue 对象,也就是消息队列,用于保存 Handler 发送的消息。
到此,Android 消息机制的三个重要角色全部出现了,分别是 Handler 、Looper 以及 MessageQueue。 一般在代码我们接触比较多的是 Handler ,但 Looper 与 MessageQueue 却是 Handler 运行时不可或缺的。
Looper
上一节分析了 Handler 的构造,其中调用了 Looper.myLooper() 方法,下面是它的源码:
static final ThreadLocal
1
2
3
|
public
static
@Nullable
Looper myLooper() {
return
sThreadLocal.get();
}
|
这个方法的代码很简单,就是从 sThreadLocal 中获取 Looper 对象。sThreadLocal 是 ThreadLocal 对象,这说明 Looper 是线程独立的。
在 Handler 的构造中,从抛出的异常可知,每个线程想要获得 Looper 需要调用 prepare() 方法,继续看它的代码:
1
2
3
4
5
6
|
private
static
void
prepare(
boolean
quitAllowed) {
if
(sThreadLocal.get() !=
null
) {
throw
new
RuntimeException(
"Only one Looper may be created per thread"
);
}
sThreadLocal.set(
new
Looper(quitAllowed));
}
|
同样很简单,就是给 sThreadLocal 设置一个 Looper。不过需要注意的是如果 sThreadLocal 已经设置过了,那么会抛出异常,也就是说一个线程只会有一个 Looper。创建 Looper 的时候,内部会创建一个消息队列:
1
2
3
4
|
private
Looper(
boolean
quitAllowed) {
mQueue =
new
MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
|
现在的问题是, Looper看上去很重要的样子,它到底是干嘛的?
回答: Looper 开启消息循环系统,不断从消息队列 MessageQueue 取出消息交由 Handler 处理。
为什么这样说呢,看一下 Looper 的 loop方法:
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
|
public
static
void
loop() {
final
Looper me = myLooper();
if
(me ==
null
) {
throw
new
RuntimeException(
"No Looper; Looper.prepare() wasn't called on this thread."
);
}
final
MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final
long
ident = Binder.clearCallingIdentity();
//无限循环
for
(;;) {
Message msg = queue.next();
// might block
if
(msg ==
null
) {
// No message indicates that the message queue is quitting.
return
;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if
(logging !=
null
) {
logging.println(
">>>>> Dispatching to "
+ msg.target +
" "
+
msg.callback +
": "
+ msg.what);
}
msg.target.dispatchMessage(msg);
if
(logging !=
null
) {
logging.println(
"<<<<< Finished to "
+ msg.target +
" "
+ msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final
long
newIdent = Binder.clearCallingIdentity();
if
(ident != newIdent) {
Log.wtf(TAG,
"Thread identity changed from 0x"
+ Long.toHexString(ident) +
" to 0x"
+ Long.toHexString(newIdent) +
" while dispatching to "
+ msg.target.getClass().getName() +
" "
+ msg.callback +
" what="
+ msg.what);
}
msg.recycleUnchecked();
}
}
|
这个方法的代码有点长,不去追究细节,只看整体逻辑。可以看出,在这个方法内部有个死循环,里面通过 MessageQueue 的 next() 方法获取下一条消息,没有获取到会阻塞。如果成功获取新消息,便调用 msg.target.dispatchMessage(msg),msg.target是 Handler 对象(下一节会看到),dispatchMessage 则是分发消息(此时已经运行在 UI 线程),下面分析消息的发送及处理流程。
消息发送与处理
在子线程发送消息时,是调用一系列的 sendMessage、sendMessageDelayed 以及 sendMessageAtTime 等方法,最终会辗转调用 sendMessageAtTime(Message msg, long uptimeMillis),代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public
boolean
sendMessageAtTime(Message msg,
long
uptimeMillis) {
MessageQueue queue = mQueue;
if
(queue ==
null
) {
RuntimeException e =
new
RuntimeException(
this
+
" sendMessageAtTime() called with no mQueue"
);
Log.w(
"Looper"
, e.getMessage(), e);
return
false
;
}
return
enqueueMessage(queue, msg, uptimeMillis);
}
private
boolean
enqueueMessage(MessageQueue queue, Message msg,
long
uptimeMillis) {
msg.target =
this
;
if
(mAsynchronous) {
msg.setAsynchronous(
true
);
}
return
queue.enqueueMessage(msg, uptimeMillis);
}
|
这个方法就是调用 enqueueMessage 在消息队列中插入一条消息,在 enqueueMessage总中,会把 msg.target 设置为当前的 Handler 对象。
消息插入消息队列后, Looper 负责从队列中取出,然后调用 Handler 的 dispatchMessage 方法。接下来看看这个方法是怎么处理消息的:
1
2
3
4
5
6
7
8
9
10
11
12
|
public
void
dispatchMessage(Message msg) {
if
(msg.callback !=
null
) {
handleCallback(msg);
}
else
{
if
(mCallback !=
null
) {
if
(mCallback.handleMessage(msg)) {
return
;
}
}
handleMessage(msg);
}
}
|
首先,如果消息的 callback 不是空,便调用 handleCallback 处理。否则判断 Handler 的 mCallback 是否为空,不为空则调用它的 handleMessage方法。如果仍然为空,才调用 Handler 自身的 handleMessage,也就是我们创建 Handler 时重写的方法。
如果发送消息时调用 Handler 的 post(Runnable r)方法,会把 Runnable封装到消息对象的 callback,然后调用 sendMessageDelayed,相关代码如下:
1
2
3
4
5
6
7
8
9
|
public
final
boolean
post(Runnable r)
{
return
sendMessageDelayed(getPostMessage(r),
0
);
}
private
static
Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return
m;
}
|
此时在 dispatchMessage中便会调用 handleCallback进行处理:
1
2
3
|
private
static
void
handleCallback(Message message) {
message.callback.run();
}
|
可以看到是直接调用了 run 方法处理消息。
如果在创建 Handler时,直接提供一个 Callback 对象,消息就交给这个对象的 handleMessage 方法处理。Callback 是 Handler 内部的一个接口:
1
2
3
|
public
interface
Callback {
public
boolean
handleMessage(Message msg);
}
|
以上便是消息发送与处理的流程,发送时是在子线程,但处理时 dispatchMessage 方法运行在主线程。
总结
至此,Android消息处理机制的原理就分析结束了。现在可以知道,消息处理是通过 Handler 、Looper 以及 MessageQueue共同完成。 Handler 负责发送以及处理消息,Looper 创建消息队列并不断从队列中取出消息交给 Handler, MessageQueue 则用于保存消息。