先看继承关系
Runnable
^
|
Thread
^
|
HandlerThread ----> Looper
Looper里面的loop()方法,提供一个while(true)的死循环和一个消息队列,看下面的代码:
Looper.java
public static final void loop() { Looper me = myLooper(); MessageQueue queue = me.mQueue; while (true) { Message msg = queue.next(); // might block //if (!me.mRun) { // break; //} if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } if (me.mLogging!= null) me.mLogging.println( ">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what ); msg.target.dispatchMessage(msg); if (me.mLogging!= null) me.mLogging.println( "<<<<< Finished to " + msg.target + " " + msg.callback); msg.recycle(); } } }
looper循环处理消息的分发,当队列里有消息的时,分发到对应的target也就是Handler对象,没有消息时,queue.next()会阻塞住,看下面的代码。
MessageQueue.java
final Message next() { boolean tryIdle = true; while (true) { long now; Object[] idlers = null; // Try to retrieve the next message, returning if found. synchronized (this) { now = SystemClock.uptimeMillis(); Message msg = pullNextLocked(now); if (msg != null) return msg; if (tryIdle && mIdleHandlers.size() > 0) { idlers = mIdleHandlers.toArray(); } } // There was no message so we are going to wait... but first, // if there are any idle handlers let them know. boolean didIdle = false; if (idlers != null) { for (Object idler : idlers) { boolean keep = false; try { didIdle = true; keep = ((IdleHandler)idler).queueIdle(); } catch (Throwable t) { Log.wtf("MessageQueue", "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } } // While calling an idle handler, a new message could have been // delivered... so go back and look again for a pending message. if (didIdle) { tryIdle = false; continue; } synchronized (this) { // No messages, nobody to tell about it... time to wait! try { if (mMessages != null) { if (mMessages.when-now > 0) { Binder.flushPendingCommands(); this.wait(mMessages.when-now); } } else { Binder.flushPendingCommands(); this.wait(); } } catch (InterruptedException e) { } catch (InterruptedException e) { } } } }
wait()是Object方法,如果线程没有消息,那线程将在wait()处阻塞,等待Handler触发它。
Runnable提供接口run()
Thread没有Looper对象的组合,即不创建消息队列
HandlerThread重写Runnable的run()方法,会创建Looper对象,调用Looper.prepare()创建自己的消息队列,看下面的代码。
HandlerThread.java
public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }
最后调用Looper.loop()进入死循环,等待消息。
创建Handler对象时可以指定消息队列,如果不指定,就用默认的消息队列,即创建handler对象的线程的(如果子线程没有,仍用主线程的)消息队列。Handler会有很多sendMessage的方法,但都是对下面这个方法的包装
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { boolean sent = false; MessageQueue queue = mQueue; if (queue != null) { msg.target = this; sent = queue.enqueueMessage(msg, uptimeMillis); } else { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); } return sent; }
看msg.target = this,也就是该消息的target设置为自己,最后Looper会调用到Handler的dispatchMessage()方法,在这个方法里面会调用handleMessage()方法,这就是我们继承Handler要重写handlerMessage()方法的原因,最后重点看queue.enqueueMessage(),
MessageQueue.java
final boolean enqueueMessage(Message msg, long when) { if (msg.when != 0) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.target == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } else if (msg.target == null) { mQuiting = true; } msg.when = when; //Log.d("MessageQueue", "Enqueing: " + msg); Message p = mMessages; if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; this.notify(); } else { Message prev = null; while (p != null && p.when <= when) { prev = p; p = p.next; } msg.next = prev.next; prev.next = msg; this.notify(); } } return true; }
最后会调用this.notify()触发上面的this.wait()继续执行,分发消息。
Android的四大组件Activity,BroadcastReceiver,Service,ContentProvider是运行在main thread中的,main thread是有Looper对象的,也就是有自己的消息队列(message queue)。他们的构造函数应该是调用prepareMainLooper()来创建主线程的消息队列,对应子线程的prepare()
当我们向一个handler发送消息的时候,实际上把消息打包(指定消息的target为自己)添加到消息队列里面去,然后由looper负责消息的分发到对应的target,也就是最后会调用到hanlder自己的handleMessage()方法。
关于子线程有没有必要创建自己的消息队列,而不跟主线程共享消息队列,我的理解是如果优先保证主线程里面的消息快速的分发出去,但是如果子线程里面频繁发送消息而没有自己的消息队列的话,会造成主线程的消息队列阻塞。
一个进程里面有一个主线程和多个子线程,那么多个线程的消息队列如何并存呢?
看Looper的prepare()方法
public void set(T value) { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values == null) { values = initializeValues(currentThread); } values.put(this, value); }
ThreadLocal里面Thread-->Looper的Hash表,通过get()和set()方法来得到Looper对象
看看示例代码,这里创建两个Handler,一个用主线程的消息队列,还一个用子线程自己的消息队列,按钮(主线程)监听点击事件,触发子线程运行,子线程创建Toast,然后又向主线程发消息,主线程也创建一个Toast。
package com.broncho.multithread; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.widget.Button; import android.widget.Toast; import android.view.View; import android.view.View.OnClickListener; public class TestActivity extends Activity implements OnClickListener{ private final String TAG = "ThreadTest"; public Handler mHandlerUseMainLoop; public MyThread mThread; public Button mButton; public final int MESSAGE_FROM_MAIN_THREAD = 0; public final int MESSAGE_FROM_SUB_THREAD = 1; public final String STRING_FROM_MAIN_THREAD = "string from main thread"; public final String STRING_FROM_SUB_THREAD = "string from sub thread"; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mButton = (Button )findViewById(R.id.button); mButton.setOnClickListener(this); mHandlerUseMainLoop = new MyHandler(Looper.getMainLooper()); mThread = new MyThread(TAG); mThread.start(); } public void onClick(View view) { switch(view.getId()) { case R.id.button: //主线程负责UI的响应,收到点击事件后,向子线程的Handler发送消息 mThread.mHandlerUseSubLoop.sendEmptyMessage(MESSAGE_FROM_MAIN_THREAD); break; } } private class MyHandler extends Handler { public MyHandler(Looper looper) { super(looper); } public void handleMessage(Message msg) { int what = msg.what; switch(what) { case MESSAGE_FROM_MAIN_THREAD: //这里的代码运行于子线程中,子线程起一个Toast Toast.makeText(TestActivity.this, STRING_FROM_MAIN_THREAD, 3000).show(); //子线程向主线程的Handler发送消息 Message message = mHandlerUseMainLoop.obtainMessage(MESSAGE_FROM_SUB_THREAD); mHandlerUseMainLoop.sendMessageDelayed(message, 4000); break; case MESSAGE_FROM_SUB_THREAD: //这里的代码运行于主线程。 Toast.makeText(TestActivity.this, STRING_FROM_SUB_THREAD, 3000).show(); break; } } } class MyThread extends Thread { private Looper mLooper; public Handler mHandlerUseSubLoop; public MyThread(String name) { super(name); } public void run() { //创建子线程自己的消息队列 Looper.prepare(); mLooper = Looper.myLooper(); mHandlerUseSubLoop = new MyHandler(mLooper); Looper.loop(); } } }