1.如何为Thread创建消息循环
Threads by default do not have a message loop associated with them
Thread默认是没有绑定消息循环的,主线程是个例外,稍后讨论主线程。
to create one, call {@link #prepare} in the thread that is to run the loop,
and then {@link #loop} to have it process messages until the loop is stopped.
创建消息循环的第一步是new Looper(),但是由于只有一个构造方法且是private,所以应调用prepare()来new出来
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); public static void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); } private Looper() { mQueue = new MessageQueue(); mRun = true; mThread = Thread.currentThread(); }sThreadLocal中保存了Looper的实例,能保证prepare在同一个Thread中只能被调用一次。
Looper的构造方法也值得一看:
它需要创建一个消息队列,同时需要保存当前Thread到成员变量mThread中。
所以,Looper、MessageQueue和Thread是一对一的关系:
一个Thread最多只能有一个Looper实例(也可以没有,主线程默认有一个,非主线程默认没有);
当你调用Looper.prepare()时,它就会创建一个Looper实例,同时与当前Thread进行绑定。
一个Looper有且只有一个MessageQueue。
public static Looper myLooper() { return sThreadLocal.get(); } public Thread getThread() { return mThread; } public static MessageQueue myQueue() { return myLooper().mQueue; } /** @hide */ public MessageQueue getQueue() { return mQueue; }
在一个while循环中,不断地从消息队列中取出Message,交给此Message绑定的Hanler却分发处理。
这个循环退出只有一种方式:某个Message的target为空。
这只有调用quit方法时才会发生,其它情况下,每个Message都会与某个Handler实例绑定。
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; while (true) { Message msg = queue.next(); // might block if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } msg.target.dispatchMessage(msg); msg.recycle(); } } } public void quit() { Message msg = Message.obtain(); // NOTE: By enqueueing directly into the message queue, the // message is left with a null target. This is how we know it is // a quit message. mQueue.enqueueMessage(msg, 0); }
下面是一个很好的示例代码:
* class LooperThread extends Thread { * public Handler mHandler; * * public void run() { * Looper.prepare(); * * mHandler = new Handler() { * public void handleMessage(Message msg) { * // process incoming messages here * } * }; * * Looper.loop(); * } * }
2.消息的处理
msg.target.dispatchMessage(msg);
每个Message的target都指向一个Handler实例,所以处理消息是有Handler的dispatchMessage方法来处理
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }当调用Hanlder的postXXX方法时,都会传递过来一个Runnable对象,这个Runnable对象被封装为callback,在消息队列循环轮到此消息后,handleCallback直接调用此Runnable的run方法。
mCallback是在Hanlder的构造方法中传递进来的,很少见到如此使用它。
最后则是每个Handler实例都要实现的handleMessage方法。
其实,某个Message最终是在哪个线程中被处理,与这个Message中target所指向的Handler有关,进一步,是与这个Handler绑定的Looper有关,更进一步,是这个Looper绑定的Thread。
看Handler的构造方法:
public Handler() { 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 = null; } public Handler(Looper looper) { mLooper = looper; mQueue = looper.mQueue; mCallback = null; }
看个简单例子:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); HandlerThread ht = new HandlerThread("thread_test"); ht.start(); Handler handler = new Handler(ht.getLooper()){ public void handleMessage(Message msg) { System.out.println("Handler.handleMessage: getId = " + Thread.currentThread().getId()); System.out.println("Handler.handleMessage: getName = " + Thread.currentThread().getName()); } }; System.out.println("Activity.onCreate: getId = " + Thread.currentThread().getId()); System.out.println("Activity.onCreate: getName = " + Thread.currentThread().getName()); handler.sendEmptyMessage(0); } } I/System.out( 2737): Activity.onCreate: getId = 1 I/System.out( 2737): Activity.onCreate: getName = main I/System.out( 2737): Handler.handleMessage: getId = 174 I/System.out( 2737): Handler.handleMessage: getName = thread_test通过运行程序后输出的log可以确定,handleMessage方法是在thread_test这个新线程中执行的,而不是在主线程中,UI线程name为main。
也不难猜测,如果只是在主线程中通过new Handler方法,那么其实还是在主线程中执行handleMessage。
所以,如果希望通过Handler执行某些耗时工作的话,一定要新创建一个线程,在新线程中构造消息循环,然后把Looper对象交给Handler。不这样的话,始终还是会在主线程执行耗时操作。
当有此类需求时,HandlerThread是个不错的类,可以帮我们更容易实现。使用方法如上。
系统服务PackageManagerService就是这么处理的。
3.关于主线程
每个应用程序都运行在单独的进程中,进程名称就是包名。每个应用程序都有一个ActivityThread实例,它就运行在该进程的主线程中。
我们既然说主线程默认就有一个消息循环,那么就看它是如何实现的,有和不同:
public static void main(String[] args) { Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); if (sMainThreadHandler == null) { sMainThreadHandler = new Handler(); } ActivityThread thread = new ActivityThread(); thread.attach(false); Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }其实与我们之前提到的没多大差异:Looper.prepareMainLooper(); 然后是Looper.loop();
所以,主线程之所以有消息循环,是因为系统已为每个应用程序创建了消息循环。但它的特别在于调用的是prepareMainLooper而非prepare。
public static void prepareMainLooper() { prepare(); setMainLooper(myLooper()); myLooper().mQueue.mQuitAllowed = false; } private static Looper mMainLooper = null; // guarded by Looper.class private synchronized static void setMainLooper(Looper looper) { mMainLooper = looper; } public synchronized static Looper getMainLooper() { return mMainLooper; }可以看到它与prepare相比,只是多了两步:一是把当前创建的Looper保存到成员变量mMainLooper中,二是设置对应的消息队列不允许quit。
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); System.out.println("Activity.onCreate: getId = " + Thread.currentThread().getId()); System.out.println("Activity.onCreate: getName = " + Thread.currentThread().getName()); new Thread() { public void run() { System.out.println("new Thread: getId = " + Thread.currentThread().getId()); System.out.println("new Thread: getName = " + Thread.currentThread().getName()); Looper.prepare(); Handler mHandler = new Handler() { //Handler mHandler = new Handler(Looper.getMainLooper()) { public void handleMessage(Message msg) { System.out.println("new Thread handleMessage: getId = " + Thread.currentThread().getId()); System.out.println("new Thread handleMessage: getName = " + Thread.currentThread().getName()); } }; mHandler.sendEmptyMessage(0); Looper.loop(); } }.start(); } }
Handler mHandler = new Handler(Looper.getMainLooper())
I/System.out( 3162): Activity.onCreate: getId = 1
I/System.out( 3162): Activity.onCreate: getName = main
Handler mHandler = new Handler()
I/System.out( 3265): Activity.onCreate: getId = 1
从这个例子可以看出,新线程中的handleMessage是在新线程中执行,我们可以通过getMainLooper方法,把handleMessage放在主线程中去执行。