Handler的主要作用是将一个任务切换到某个指定的线程去执行。今天从JVM的角度看看它是如何运作起来的。
老规矩先上图
类图
Handler.png在线程1执行的代码
现在假设一个情景:
有两个线程,线程1和线程2,第一步:在线程1中调用Looper.prepare()。第二步创建一个Handler对象handler。第三步调用Looper.loop()。
在线程2中调用handler.sendMessage()发送消息,那最终这个消息会在线程1中被handler.handleMassage()处理。
第一步:我们看下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)); //只有在线程1可以获取该Looper对象
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed); //创建MessageQueue
mThread = Thread.currentThread();
}
创建了一个Looper对象,并将它设置到ThreadLocal对象之中,那么只能在线程1通过ThreadLocal.get获取到这个Looper对象。对ThreadLocal不熟悉的可以看我的ThreadLocal源码分析。
第二步:创建Handler(在线程1执行)
public Handler() {
this(null, false);
}
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(); //获取线程1的Looper对象
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; //获取线程1的MessageQueue
mCallback = callback;
mAsynchronous = async;
}
我们在线程1创建了Handler,创建过程中保存了线程1的MessageQueue和Looper的引用。
第三步:调用Looper.run开启事件循环
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;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) { //无限循环
Message msg = queue.next(); // might block,从消息队列获取下一个message,可能阻塞
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// 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);
}
msg.target.dispatchMessage(msg); //msg.target就是Handler对象,所以这里调用Handler.dispatchMessage处理这个message
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
开启无限循环,从消息队列获取消息,调用Handler.dispatchMessage处理消息。
到目前为止都是在线程1执行的,我们看创建了哪些对象。
Handler内存分布.png
这个Handler是所有线程都可访问的,Looper和MessageQueue只能被线程1访问。
在线程2执行的方法
假设这时线程切换到了线程2,线程2中我们调用了handler.sendMessage发送了一个Message。
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
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) {
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; //message的target指向这个handler
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis); //加入线程1中创建的MessageQueue中
}
最关键的操作时将message加入线程1中创建的MessageQueue中。
再次切换到线程1
假设线程再次切换到线程1,Looper的loop会从MessageQueue获取刚加入的Message,并调用它target引用的handler的dispatchMessage方法处理当前的message。到这里就达到,在线程2发送消息,在线程1处理消息的目的。是不是很巧妙?
支持原创,转载请注明出处。
如果觉得写得不错,欢迎关注我。github:https://github.com/gatsbydhn
网友评论