上一篇文章,我们谈到了电话Handler的sendMessage方法,最后,我们将进入一个电话 sendMessageAtTime方法,例如下列:
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); }
在这里。我们看到了MessageQueue和enqueueMessage等变量跟方法,我们能够想到,在Handler的实现的机制中,一定存在着一个消息队列。而它存放了我们创建的众多消息(Message)对象。
从这里,我们就会開始去探寻隐藏在 Handler对象后面的那一些我们想知道的实现机制了。
首先,我们还是从 Handler的创建開始说起,在上一篇文章,我们是通过 new Handler的方法来创建的,代码例如以下:
private Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case MSG_ID_1: Log.v("Test", "Toast called from Handler.sendMessage()"); break; case MSG_ID_2: String str = (String) msg.obj; Log.v("Test", str); break; } } };
显然。我们要去看一下Handler的构造函数,例如以下:
public Handler() { this(null, false); } public Handler(Callback callback) { this(callback, false); } public Handler(Looper looper) { this(looper, null, false); } public Handler(Looper looper, Callback callback) { this(looper, callback, false); } public Handler(boolean async) { this(null, async); } 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; } public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }
我们能够看到。真正实现的构造函数。事实上仅仅有以下两个。例如以下:
public Handler(Callback callback, boolean async) { .... } public Handler(Looper looper, Callback callback, boolean async) { ... }
这两个的区别就在于是否有參数Looper。而Looper是一个线程相关的对象。
何谓线程相关的变量?就是线程间不能共享的对象,仅仅在本线程内有作用的对象。
那么Looper对象的作用是什么?
从我个人的理解,Looper类就是对MessageQueue的封装。它主要做的是两件事:
1)构造Looper对象,初始化MessageQueue。我们能够从其构造函数看到:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
显然。MessageQueue正是在创建Looper的时候初始化的。
我们还注意到。这个构造函数是private的。而它则是被Looper.prepare方法调用的,例如以下:public static void prepare() { prepare(true); } 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)); }
能够看到,Loop对象被创建之后,会被放到ThreadLocal变量中,而ThreadLocal正是线程局部变量,这说明了关于Looper的一个特性:
每个线程中都仅仅能有一个Looper对象。
2)调用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; .... for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } ... msg.target.dispatchMessage(msg); .... msg.recycle(); } }
从上面的代码中。我们能够看到,在一个无限循环中,会从MessageQueue中获得消息,然后通过msg.target.dispatchMessage(msg)方法调用。处理消息。最后将消息进行回收。
在这里。我们先不关心dispatchMessage方法。我们先跑一下题。看一下recycle方法里面做了什么事吧,例如以下:
private static Message sPool; private static int sPoolSize = 0; private static final int MAX_POOL_SIZE = 50; /** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. */ public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; sPoolSize--; return m; } } return new Message(); } public void recycle() { clearForRecycle(); synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
从上面的代码中。我们能够看到,Message对象本身有一个next的字段指向另外一个Message,也就是说,能够通过链表的方式将众多的Message给串起来,变成一个链表的消息池sPool。
而在这里,当调用recycle方法,就会将当前Message对象,先clearForRecycle之后。再加入到 sPool的头部中。而当我们通过Message的obtain方法的时候,我们事实上也是从sPool中拿 出一个空的Message对象。
相信看到这里,大家就了解了上一篇文章中我说。为什么建议大家使用Message.obtain方法去获取消息对象了吧。
接下来,我们再回到正题上。
从上面关于Handler的创建和关于Looper的描写叙述中,我们能够得出这样一个结论:
在每个线程中,假设我们要创建Handler,那么此线程中就必须有一个Looper对象,而这个Looper对象中又封装了一个MessageQueue对象来对Message进行管理。
所以,假设我们要在一个新线程中使用handler的话,我们就必须通过调用Loop.prepare()方法,为此线程创建一个Looper对象。官方给出的代码例如以下:
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(); } }
当然,仅仅有理论当然是不行的。我们还是得通过一个样例来看一下详细的效果,例如以下:
public class MainActivity extends ActionBarActivity { private static final int MSG_ID_1 = 1; private static final int MSG_ID_2 = 2; class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { Log.v("Test", "Id of LooperThread : " + Thread.currentThread().getId()); switch (msg.what) { case MSG_ID_1: Log.v("Test", "Toast called from Handler.sendMessage()"); break; case MSG_ID_2: String str = (String) msg.obj; Log.v("Test", str); break; } } }; Looper.loop(); } } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.v("Test", "Id of MainThread : " + Thread.currentThread().getId()); LooperThread looperThread = new LooperThread(); looperThread.start(); while(looperThread.mHandler == null){ } Message message = Message.obtain(); message.what = MSG_ID_1; looperThread.mHandler.sendMessage(message); Message msg2 = Message.obtain(); msg2.obj = "I'm String from Message 2"; msg2.what = MSG_ID_2; looperThread.mHandler.sendMessage(msg2); } }
相应的结果例如以下:
10-27 16:48:44.519: V/Test(20837): Id of MainThread : 1 10-27 16:48:44.529: V/Test(20837): Id of LooperThread : 68421 10-27 16:48:44.529: V/Test(20837): Toast called from Handler.sendMessage() 10-27 16:48:44.529: V/Test(20837): Id of LooperThread : 68421 10-27 16:48:44.529: V/Test(20837): I'm String from Message 2
那事实上在这里有一个问题,为什么我们寻常能够直接去创建Handler对象,而不须要去调用UI线程的Looper.prepare和loop等方法它?
当然,这当然是需要。这个步骤是仅Android系统帮我们做,所以默认主线程不再需要做这些初始化。
好,本文,我们了解到一个线程,Looper,Handler, MessageQueue 和 Message 等之间的一些相关,但主要用于Looper知识对象。
结束。