在android开发过程中,我们经常有更新UI的操作。如网络请求后,更新UI控件。此时我们第一想法就是用Handler,确实如此。由于Android开发规范限制,我们不能在非主线程(UI线程,即ActivityThread)里面直接操作UI控件,否则会出现异常,Only the original thread that created a view....(Android线程并不是线程安全的,在多线程中并发操作UI控件可能会发生不可预计的问题)。
现在我并不是想讲Handler 如何操作UI控件,而是为什么Handler可以操作UI控件。来自官方文档一段话
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
说人话就是:Handler可以将一个任务切换到Handler所在的线程中去执行任务。
为啥android需要提供一个在某个线程中执行任务这种功能?这个就解决了在非UI线程中操作UI控件会抛出异常,这就是Handler存在的意义。Handler可以把UI控件更新操作切换到UI主线程中执行,这个就决解了在子线程中如何更新UI主线程控件的问题。总之一句话:Handler可以将Handler中的业务逻辑切换到创建Handler所在的线程中执行。
现在我们知道Handler是将控件操作切换至UI主线程中执行,但是,这个如何切换的呢?具体是怎么切换的呢?
我的理解是这样的:整个流程涉及到Looper、MessageQueue、Handler。
一,Handler通过send方法发送一个消息Message,发送到当前线程的MessageQueue中,
二,Looper 通过loop方法不断地从MessageQueue中抽取Message(在主线程中,默认是包含Looper)
public static final void loop() {
72 Looper me = myLooper();//从该线程中取出对应的looper对象
73 MessageQueue queue = me.mQueue;//取消息队列对象...
74 while (true) {
75 Message msg = queue.next(); // might block取消息队列中的一个待处理消息..
76 //if (!me.mRun) {//是否需要退出?mRun是个volatile变量,跨线程同步的,应该是有地方设置它。
77 // break;
78 //}
79 if (msg != null) {
80 if (msg.target == null) {
81 // No target is a magic identifier for the quit message.
82 return;
83 }
84 if (me.mLogging!= null) me.mLogging.println(
85 ">>>>> Dispatching to " + msg.target + " "
86 + msg.callback + ": " + msg.what
87 );
88 msg.target.dispatchMessage(msg);
89 if (me.mLogging!= null) me.mLogging.println(
90 "<<<<< Finished to " + msg.target + " "
91 + msg.callback);
92 msg.recycle();
93 }
94 }
95 }
以上可以看到,当有loop检测有message信息的时候, 会调用msg.target.dispatchMessage(msg);这个msg.target是指Handler。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
handleMessage方法是不是有点熟悉?对,就是Handler的回调方法
这个流程指出了,handler发出消息给messageQueue,looper不断从messageQueue里取出消息,然后执行handlerMessage方法。handlerMessage方法具体的实现在Handler回调里面。
结束了?? “Handler是将控件操作切换至UI主线程中执行”这句话还没解释的通啊。
通过网上资料查询,我知道在ActivityThread创建时,会初始化Looper,也就是说默认情况下Looper在主线程中会创建的。
那我们现在明白,在子线程中可以通过Handler更新UI控件的原因了。Handler可以将Handler中的业务逻辑切换到创建Handler所在的线程中执行。而Looper恰恰是属于主线程的。
下一篇说说Handler、MessageQueue、Looper