在日常开发中,我们经常要用到消息的通信机制,比如网络请求,在子线程中请求到数据后,切换到主线程(也叫ui线程-activityThread)去更新数据。
在这一过程中,有几个比较重要的类是我们要熟悉或者了解的,分别是–handler Looper Message Messagequeue ThreadLocal。
这里我们就不详细的去分析每个类的底层逻辑了,只会在要用到的相关方法时再去分析下。
那我们就直接切到正题吧,我们平时需要用到handler的时候绝大部分都是直接在主线程中创建handler并初始化的,然后在子线程中去把数据消息发送到主线程去处理,比如这样。。
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 0:
//todo
break;
}
}
};
发送一条消息
new Thread(new Runnable() {
@Override
public void run() {
//这里请求网络数据,然后把数据通过message发送
Message message=Message.obtain();
message.obj="如果不是基本数据类型的可以通过此字段来发送";
message.what=0;
handler.sendMessage(message);
}
}).start();
好了,这是一条很基本的消息发送,很容易理解,接下来,我们去分析为什么在子线程通过 handler.sendMessage(message);就能把消息给发送到了主线程呢?我们跟着他的方法一步步的下去看,点进handler的sendMessage(message)去看
public final boolean sendMessage(Message msg) {
return this.sendMessageDelayed(msg, 0L);
}
ok,调用了 this.sendMessageDelayed(msg, 0L),这里的第二个参数是延迟发送的参数,如果我们想延迟发送消息的话,可以一开始直接就调用handler.sendMessageDelayed(),这样就可以延迟发送消息了。
我们接着点进去sendMessageDelayed()这个方法里面看看,
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if(delayMillis < 0L) {
delayMillis = 0L;
}
return this.sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
好吧,判断了一下延迟的时间,然后调用了this.sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);,接着点进去look look
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = this.mQueue;
if(queue == null) {
RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
} else {
return this.enqueueMessage(queue, msg, uptimeMillis);
}
}
嗯,主角之一MessageQueue粉墨登场了,让我们我们来会会它,可以看到这里直接就把 this.mQueue赋值给了新创建的queue了,那 this.mQueue是在哪创建的呢,这是我想写这篇博客的原因之一。其实 this.mQueue是主线程的MessageQueue,而非这个子线程自己的MessageQueue,因为主线程在调用main函数之后就已经创建好了MessageQueue,具体我们看下代码
public static void main(String[] args) {
Trace.traceBegin(64L, "ActivityThreadMain");
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
EventLogger.setReporter(new ActivityThread.EventLoggingReporter(null));
File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("");
> Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if(sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Trace.traceEnd(64L);
> Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
这里先说下,其实MessageQueue是Looper的一个成员变量,它在Looper的构造函数中初始化,当调用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");
} else {
sThreadLocal.set(new Looper(quitAllowed));
}
}
这里可以看到Looper是在 sThreadLocal.set(new Looper(quitAllowed));中被创建,这个sThreadLocal是ThreadLocal,也是我们的主角之一,它主要是用来存储线程内变量的,接下来我们进去Looper的构造函数中看。
private Looper(boolean quitAllowed) {
this.mQueue = new MessageQueue(quitAllowed);
this.mThread = Thread.currentThread();
}
嗯哼,终于看到,原来this.mQueue是在这里被创建的,到这里我们先捋一下思路,调用了Looper.prepare之后才创建MessageQueue,但是我们好像从来没有调用过Looper.prepare()函数呀,那MessageQueue是哪来的呀,别急,慢慢来,喝口水消消性子,等贫僧念念经。。。
public Handler() {
this((Handler.Callback)null, false);
}
public Handler(Handler.Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, (Handler.Callback)null, false);
}
public Handler(Looper looper, Handler.Callback callback) {
this(looper, callback, false);
}
public Handler(boolean async) {
this((Handler.Callback)null, async);
}
public Handler(Handler.Callback callback, boolean async) {
this.mLooper = Looper.myLooper();
if(this.mLooper == null) {
throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
} else {
this.mQueue = this.mLooper.mQueue;
this.mCallback = callback;
this.mAsynchronous = async;
}
}
这里看到handler有几个构造函数,我们创建handler的时候并没有传入任何参数,所以调用了handler的无参构造函数,然后无参构造函数又调用有两个参数的那个构造函数 public Handler(Handler.Callback callback, boolean async),然后看到这行 this.mLooper = Looper.myLooper();
看到没,Looper是在这里被赋值的,我们进去Looper.myLooper()这个方法看
public static Looper myLooper() {
return (Looper)sThreadLocal.get();
}
哦,原来Looper是在这里获得的,那为什么通过(Looper)sThreadLocal.get()就能获得呢,因为我们说过ThreadLocal是专门存储线程内信息的,而Looper也属于线程内的变量,当然也就被存储在ThreadLocal里面咯,而在每个线程内调用(Looper)sThreadLocal.get()所获得的值是不同的,因为在(Looper)sThreadLocal.get()的内部会通过Thread.currentThread去获取每个线程对应的值,这里我们就不贴代码了,有需要了解的爷请自行查看源码哈,这里请允许小弟偷下懒呗。
接着回到话题,因为我们是在主线程创建的handler,所以理所当然的最后获取到的Looper就可以一口咬定是属于主线程的啦,而更理所当然的MessageQueue也是属于主线程的啦,因为它是在Looper的构造函数中被创建的嘛!那么,通过handler.sendMessage()发送的message自然就是存进主线的MessageQueue中咯,而在
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 0:
//todo
break;
}
}
};
中取出的message也是从主线程的MessageQueue取出的,接下来我们回到上面的步伐接着看,
刚刚我们看到
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = this.mQueue;
if(queue == null) {
RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
} else {
return this.enqueueMessage(queue, msg, uptimeMillis);
}
}
看到调用了this.enqueueMessage(queue, msg, uptimeMillis)这个方法,点进去看看
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if(this.mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
可以看到,把handler本身赋值给了message的target字段,因为这个方法是在handler类里面调用的,所以this就代表了handler本身。然后看到queue.enqueueMessage(msg, uptimeMillis);这里的queue就是从主线程所获取来的MessageQueue,就是在这个方法中插入一条消息到消息队列中的。好了,消息存进去了,那么如何取出消息的呢?
取出消息的操作是在Looper.loop中,我们去看看
public static void loop() {
Looper me = myLooper();
if(me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
} else {
MessageQueue queue = me.mQueue;
Binder.clearCallingIdentity();
long ident = Binder.clearCallingIdentity();
while(true) {
Message msg = queue.next();
if(msg == null) {
return;
}
Printer logging = me.mLogging;
if(logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what);
}
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long traceTag = me.mTraceTag;
if(traceTag != 0L && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
long start = slowDispatchThresholdMs == 0L?0L:SystemClock.uptimeMillis();
long end;
try {
msg.target.dispatchMessage(msg);
end = slowDispatchThresholdMs == 0L?0L:SystemClock.uptimeMillis();
} finally {
if(traceTag != 0L) {
Trace.traceEnd(traceTag);
}
}
long newIdent;
if(slowDispatchThresholdMs > 0L) {
newIdent = end - start;
if(newIdent > slowDispatchThresholdMs) {
Slog.w("Looper", "Dispatch took " + newIdent + "ms on " + Thread.currentThread().getName() + ", h=" + msg.target + " cb=" + msg.callback + " msg=" + msg.what);
}
}
if(logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
newIdent = Binder.clearCallingIdentity();
if(ident != newIdent) {
Log.wtf("Looper", "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();
}
}
}
这段代码有点长,我们挑重点来看就行了,其实在看源码的时候,我们没有必要把每行代码都看懂,只要看明白大概流程就行了,因为有些源码不是一个人写的,你很难去揣摩别人的每一行代码的作用,那样你会走火入魔的(不恰当),不扯了,回到主题
MessageQueue queue = me.mQueue;
这里首先获取到了我们存进去消息的那个MessageQueue,然后就进入到了阻塞循环体,我们看重点
Message msg = queue.next();
if(msg == null) {
return;
}
在循环体中通过queue.next();取出消息(同时把该message从消息队列中移除),这里可以看到,当msg ==null时,就不会往下走了,在这里就阻塞住了,接着往下看
try {
msg.target.dispatchMessage(msg);
end = slowDispatchThresholdMs == 0L?0L:SystemClock.uptimeMillis();
} finally {
if(traceTag != 0L) {
Trace.traceEnd(traceTag);
}
}
看这句 msg.target.dispatchMessage(msg);这里的 msg.target就是我们先前发送消息的时候传入的handler对象,点进去dispatchMessage(msg)方法看看
public void dispatchMessage(Message msg) {
if(msg.callback != null) {
handleCallback(msg);
} else {
if(this.mCallback != null && this.mCallback.handleMessage(msg)) {
return;
}
this.handleMessage(msg);
}
}
看这句msg.callback != null,这里的callback其实是Runnable对象,当我们通过handler.post系列函数发送消息的时候,这里的callback就不会为null,但我们是通过send系列函数发送的,所以这里它为空,接着进入到
else {
if(this.mCallback != null && this.mCallback.handleMessage(msg)) {
return;
}
this.handleMessage(msg);
}
this.mCallback != null && this.mCallback.handleMessage(msg)这里的mCallback是Handler.Callback mCallback;如果我们创建handler时传入Callback,它就不会为空,还记得handler有这样一个构造函数吧
public Handler(Handler.Callback callback) {
this(callback, false);
}
所以它也是空,接着肯定的要调用 this.handleMessage(msg);方法,我们进去看
public void handleMessage(Message msg) {
}
看到没,空空如也。。。
这个方法就是我们创建handler时重写的
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 0:
//todo
break;
}
}
};
终于,经过了九九六十一,回到了主线程的
public void handleMessage(Message msg) {
switch (msg.what){
case 0:
//todo
break;
}
handleMessage(Message msg)方法中,这里就可以就行ui刷新的工作啦,咧咧咧,我不听,我不听,我就要在子线程刷新
额。陛下,冷静点,到饭点了,我们吃饭去吧。。。。。。。。
最后说明一点,本文纯属个人理解,可能不可避免有错误,各位看官如果发现有错误,请给指出啊,别有误人子弟我就要跳黄河洗不清啦,哈哈哈。。。。