简介
在 Android 中,只有主线程才能操作 UI,但是主线程不能进行耗时操作,否则会阻塞线程,产生 ANR 异常,所以常常把耗时操作放到其它子线程进行。如果在子线程中需要更新 UI,一般是通过?Handler
?发送消息,主线程接受消息并且进行相应的逻辑处理。除了直接使用?Handler
,还可以通过 View 的?post
?方法以及 Activity 的?runOnUiThread
?方法来更新 UI,它们内部也是利用了?Handler
。在上一篇文章?Android AsyncTask源码分析?中也讲到,其内部使用了?Handler
?把任务的处理结果传回 UI 线程。
本文深入分析 Android 的消息处理机制,了解?Handler
?的工作原理。
Handler
先通过一个例子看一下?Handler
?的用法。
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
的构造方法的源码:
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<Looper> sThreadLocal = new ThreadLocal<Looper>(); public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
这个方法的代码很简单,就是从?sThreadLocal
?中获取?Looper
?对象。sThreadLocal
?是?ThreadLocal
?对象,这说明?Looper
?是线程独立的。
在?Handler
?的构造中,从抛出的异常可知,每个线程想要获得?Looper
?需要调用?prepare()
?方法,继续看它的代码:
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
?的时候,内部会创建一个消息队列:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
现在的问题是,?Looper
看上去很重要的样子,它到底是干嘛的?
回答:?Looper
?开启消息循环系统,不断从消息队列?MessageQueue
?取出消息交由?Handler
?处理。
为什么这样说呢,看一下?Looper
?的?loop
方法:
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)
,代码如下:
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
?方法。接下来看看这个方法是怎么处理消息的:
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
,相关代码如下:
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
进行处理:
private static void handleCallback(Message message) { message.callback.run(); }
可以看到是直接调用了?run
?方法处理消息。
如果在创建?Handler
时,直接提供一个?Callback
?对象,消息就交给这个对象的?handleMessage
?方法处理。Callback
?是?Handler
内部的一个接口:
public interface Callback { public boolean handleMessage(Message msg); }
以上便是消息发送与处理的流程,发送时是在子线程,但处理时?dispatchMessage
?方法运行在主线程。
总结
至此,Android消息处理机制的原理就分析结束了。现在可以知道,消息处理是通过?Handler
?、Looper
?以及?MessageQueue
共同完成。?Handler
?负责发送以及处理消息,Looper
?创建消息队列并不断从队列中取出消息交给?Handler
,?MessageQueue
?则用于保存消息。