首先感谢在看的读者们,因为这是我第一次写博客,可能写的不太好,大神勿喷、大神勿喷、大神勿喷。
好了废话不多说,下面进入我们的正题。
下面请看源码。。。。。。
===
『眼镜都带上了,楼主就让我看这个呀』
哈哈,当然不是呀。我只是想说 所有学习的东西都是从 hellow world 开始,所以写了一个大大的Hellow world,酝酿一下。
首先我们都知道每一个app的入口都是main方法开始运行,那说啥,咱们点击去看一下把
main方法是放在final 修饰的ActivityThread类中。代码如下:
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
我们先看一下第一行代码
Looper.prepareMainLooper();
这行代码就是准备ui线程的Looper。 可能大家有个疑问,平时我们创建Loop对象就是通过Looper.prepare();进行创建。
他俩有什么区别呢?
主要区别在于他们方法里面都调用了prepare(boolean quitAllowed) 方法,只是传值不一样。我们点击进去看看。quitAllowed最后赋值给mQuitAllowed参数。
void quit(boolean safe) {
// 如果主线程退出抛出异常
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
//下面的if语句防止同步问题
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
//safe 是否选择安全退出模式
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
好了,看了上面的代码,我们明白了它两者的区别了吧。prepareMainLooper方法和prepare方法区别在于是否允许Looper.loop() 结束循环
如果想退出循环调用 Looper.myLooper().quit();或者Looper.myLooper().quitSafely();
接下来,我们看一下Looper.prepare();方法是怎么创建Looper的
private static void prepare(boolean quitAllowed) {
//通过下面的3行代码,我们可以准确的确定一个线程中只能有一个Looper对象
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//把创建出来的Looper放入ThreadLocal静态常量中
sThreadLocal.set(new Looper(quitAllowed));
}
sThreadLocal.get() 方法实现方式类似于hashmap的实现原理 根据当前线程得到一个ThreadLocalMap静态内部类,判断是否为空,不为空在通过getEntry得到Entity对象,然后通过.value得到当前的Looper。
sThreadLocal.set(new Looper(quitAllowed)) 根据当前线程得到一个ThreadLocalMap静态内部类,判断是否为空,不为空重新设置(修改或者添加),为空则创建。//new Looper()构造方法中
private Looper(boolean quitAllowed) {
//创建Looper 的时候同时也创建了一个MessageQueue对象。我们可以的出一个结论:一个线程只有一个Looper对象 一个Looper也只有一个MessageQueue对象
mQueue = new MessageQueue(quitAllowed);
//得到当前线程
mThread = Thread.currentThread();
}
从上面的代码我们能看到Looper、MessageQueue的关系。Looper.prepare()的时候会创建一个Looper对象放入ThreadLocal中,同时创建looper的时候,也创建了MessageQueue对象。
接着我们看下Handler是怎么把Message放入MessageQueue
首先Handler 发送消息是通过sendMessage方法
sendMessage调用了sendMessageDelayed方法,sendMessageDelayed方法调用sendMessageAtTime方法
在sendMessageAtTime 我们可以看到得到了一个MessageQueue对象,然后在调用enqueueMessage方法传入MessageQueue和Message。方法中Message设置target为创建好的Handler对象,然后MessageQueue通过enqueueMessage把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;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
剩下的任务就交给了Looper.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;
}
......
final long end;
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
......
}
}
代码首先通过myLooper()方法得到了一个Looper对象 ,而myLooper()方法其实调用了sThreadLocal.get()方法,把之前保存好的Looper对象取出来。得到Looper对象后,在把Looper对象里面的MessageQueue得到。
接着for循环开始,queue.next()方法不断从MessageQueue中拿出Message信息,然后通过之前设置好的target值进行dispatchMessage方法会调发送给Ui线程 进行更新ui操作。
其实细心的同事可以看到dispatchMessage回调时候还会执行handleMessage方法。在这里就不细说了。代码很简单,点击去看看就明白了。
下面做一下总结:
程序启动的时候默认会创建一个Looper对象和MessageQueue对象
Handler发送消息的时候,会把Message信息保存到MessageQueue中,并设置target为当前的Handler
最后Looper.loop() 方法把MessageQueue里面的Message信息取出来,得到Message里面的target,调用dispatchMessage()把Message传入,更新UI线程
面试问题总结:
Android使用Handler实现子线程与子线程、主线程之间通信