在Android开发当中,Thread、Handler、Looper这几个类是特别常见,在刚开始学习Android的时候对这些类可能并不是很清晰。下面我们就一起从源码的角度剖析一下这几个类的工作原理。
Thread
首先是Thread, 我们都知道一个Thread就是一个线程对象,只要在run方法中填写自己的代码然后启动该线程就可以实现多线程操作。例如 :
- new Thread(){
- public void run() {
- // 耗时的操作
- };
- }.start();
示例图如下 :
Android应用程序的入口为ActivityThread.main方法,详情请参考Android应用程序进程启动过程的源代码分析,UI线程的消息循环就是在这个方法中创建的,源码如下:
- public static void main(String[] args) {
- SamplingProfilerIntegration.start();
- CloseGuard.setEnabled(false);
- Environment.initForCurrentUser();
- // Set the reporter for event logging in libcore
- EventLogger.setReporter(new EventLoggingReporter());
- Process.setArgV0("<pre-initialized>");
- Looper.prepareMainLooper();// 1、创建消息循环Looper
- ActivityThread thread = new ActivityThread();
- thread.attach(false);
- if (sMainThreadHandler == null) {
- sMainThreadHandler = thread.getHandler(); // UI线程的Handler
- }
- AsyncTask.init();
- if (false) {
- Looper.myLooper().setMessageLogging(new
- LogPrinter(Log.DEBUG, "ActivityThread"));
- }
- Looper.loop(); // 2、执行消息循环
- throw new RuntimeException("Main thread loop unexpectedly exited");
- }
Handler
在我们在子线程中执行完耗时操作后很多情况下我们需要更新UI,但我们都知道,不能在子线程中更新UI。此时最常用的手段就是通过Handler将一个消息post到UI线程中,然后再在Handler的handleMessage方法中进行处理。 但是有一个点要注意,那就是该Handler必须在主线程中创建!! 简单示例如下:
- class MyHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- // 更新UI
- }
- }
- MyHandler mHandler = new MyHandler() ;
- // 开启新的线程
- new Thread(){
- public void run() {
- // 耗时操作
- mHandler.sendEmptyMessage(123) ;
- };
- }.start();
为什么必须要这么做呢?其实每个Handler都会关联一个消息队列,消息队列被封装在Lopper中,而每个Looper又会关联一个线程(ThreadLocal),也就是每个消息队列会关联一个线程。Handler就是一个消息处理器,将消息投递给消息队列,然后再由对应的线程从消息队列中挨个取出消息,并且执行。默认情况下,消息队列只有一个,即主线程的消息队列,这个消息队列是在ActivityThread.main方法中创建的,通过Lopper.prepareMainLooper()来创建,然后最后执行Looper.loop()来启动消息循环。那么Handler是如何关联消息队列以及线程的呢?我们看看如下源码 :
- public Handler() {
- 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(); // 获取Looper
- if (mLooper == null) {
- throw new RuntimeException(
- "Can't create handler inside thread that has not called Looper.prepare()");
- }
- mQueue = mLooper.mQueue; // 获取消息队列
- mCallback = null;
- }
- /**
- * Return the Looper object associated with the current thread. Returns
- * null if the calling thread is not associated with a Looper.
- */
- public static Looper myLooper() {
- return sThreadLocal.get();
- }
- /**
- * Initialize the current thread as a looper, marking it as an
- * application's main looper. The main looper for your application
- * is created by the Android environment, so you should never need
- * to call this function yourself. See also: {@link #prepare()}
- */
- public static void prepareMainLooper() {
- prepare();
- setMainLooper(myLooper());
- myLooper().mQueue.mQuitAllowed = false;
- }
- private synchronized static void setMainLooper(Looper looper) {
- mMainLooper = looper;
- }
- /** Initialize the current thread as a looper.
- * This gives you a chance to create handlers that then reference
- * this looper, before actually starting the loop. Be sure to call
- * {@link #loop()} after calling this method, and end it by calling
- * {@link #quit()}.
- */
- public static void prepare() {
- if (sThreadLocal.get() != null) {
- throw new RuntimeException("Only one Looper may be created per thread");
- }
- sThreadLocal.set(new Looper());
- }
Looper与MessageQueue
创建了Looper后,如何执行消息循环呢?通过Handler来post消息给消息队列( 链表 ),那么消息是如何被处理的呢?答案就是在消息循环中,消息循环的建立就是通过Looper.loop()方法。源码如下 :
- /**
- * Run the message queue in this thread. Be sure to call
- * {@link #quit()} to end the loop.
- */
- public static void loop() {
- Looper me = myLooper();
- if (me == null) {
- throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
- }
- MessageQueue queue = me.mQueue; // 1、获取消息队列
- // 代码省略
- while (true) { // 2、死循环,即消息循环
- Message msg = queue.next(); // 3、获取消息 (might block )
- if (msg != null) {
- if (msg.target == null) {
- // No target is a magic identifier for the quit message.
- return;
- }
- long wallStart = 0;
- long threadStart = 0;
- // 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);
- wallStart = SystemClock.currentTimeMicro();
- threadStart = SystemClock.currentThreadTimeMicro();
- }
- msg.target.dispatchMessage(msg); // 4、处理消息
- // 代码省略
- msg.recycle();
- }
- }
- }
最后我们看看消息处理机制,我们看到代码中第4步通过msg.target.dispatchMessage(msg)来处理消息。其中msg是Message类型,我们看源码 :
- public final class Message implements Parcelable {
- public int what;
- public int arg1;
- public int arg2;
- public Object obj;
- int flags;
- long when;
- Bundle data;
- Handler target; // target处理
- Runnable callback; // Runnable类型的callback
- // sometimes we store linked lists of these things
- Message next; // 下一条消息,消息队列是链式存储的
- // 代码省略 ....
- }
从源码中可以看到,target是Handler类型。实际上就是转了一圈,通过Handler将消息投递给消息队列,消息队列又将消息分发给Handler来处理。我们继续看
- /**
- * Subclasses must implement this to receive messages.
- */
- public void handleMessage(Message msg) {
- }
- private final void handleCallback(Message message) {
- message.callback.run();
- }
- /**
- * Handle system messages here.
- */
- public void dispatchMessage(Message msg) {
- if (msg.callback != null) {
- handleCallback(msg);
- } else {
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {
- return;
- }
- }
- handleMessage(msg);
- }
- }
- public final boolean post(Runnable r)
- {
- return sendMessageDelayed(getPostMessage(r), 0);
- }
- private final Message getPostMessage(Runnable r) {
- Message m = Message.obtain();
- m.callback = r;
- return m;
- }
- public final boolean sendMessageDelayed(Message msg, long delayMillis)
- {
- if (delayMillis < 0) {
- delayMillis = 0;
- }
- return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
- }
- public boolean sendMessageAtTime(Message msg, long uptimeMillis)
- {
- boolean sent = false;
- MessageQueue queue = mQueue;
- if (queue != null) {
- msg.target = this; // 设置消息的target为当前Handler对象
- sent = queue.enqueueMessage(msg, uptimeMillis); // 将消息插入到消息队列
- }
- else {
- RuntimeException e = new RuntimeException(
- this + " sendMessageAtTime() called with no mQueue");
- Log.w("Looper", e.getMessage(), e);
- }
- return sent;
- }
可以看到,在post(Runnable r)时,会将Runnable包装成Message对象,并且将Runnable对象设置给Message对象的callback字段,最后会将该Message对象插入消息队列。sendMessage也是类似实现 :
- public final boolean sendMessage(Message msg)
- {
- return sendMessageDelayed(msg, 0);
- }
子线程中创建Handler为何会抛出异常 ?
- new Thread(){
- Handler handler = null;
- public void run() {
- handler = new Handler();
- };
- }.start();
- /**
- * Default constructor associates this handler with the queue for the
- * current thread.
- *
- * If there isn't one, this handler won't be able to receive messages.
- */
- public Handler() {
- // 代码省略
- mLooper = Looper.myLooper(); // 获取myLooper
- if (mLooper == null) {
- throw new RuntimeException(
- "Can't create handler inside thread that has not called Looper.prepare()");// 抛出异常
- }
- mQueue = mLooper.mQueue;
- mCallback = null;
- }
我们可以看到,当mLooper对象为空时,抛出了该异常。这是因为该线程中的Looper对象还没有创建,因此sThreadLocal.get()会返回null。解决方法如下 :
- new Thread(){
- Handler handler = null;
- public void run() {
- Looper.prepare(); // 1、创建Looper,并且会绑定到ThreadLocal中
- handler = new Handler();
- Looper.loop(); // 2、启动消息循环
- };
- }.start();