上一篇文章,我们讲到在调用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);
}
从这里,我们就会开始去探寻隐藏在 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;
}
}
};
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类就是对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));
}
每一个线程中都只能有一个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();
}
}
在这里,我们先不关心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++;
}
}
}
而在这里,当调用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
当然,这肯定也是需要的,只是这一步是由Android系统帮我们做了,所以默认的主线程就不再需要去做这些初始化。
好了,这一篇文章,我们就了解了关于线程,Looper,Handler, MessageQueue 和 Message 等之间的一些关联,而主要是对于Looper对象的认识。
结束。