首先明白3个问题:Handler 是什么?Handler 拿来干什么?Handler 怎么使用?
前言:为什么会出现Handler?
我们都知道Android 的UI线程(即主线程)是线程不安全的,一切引起UI变化的操作均需在主线程中执行,而更新UI的操作往往是在一些耗时操作之后的,比如网络请求、IO操作、文件读写等这些耗时操作必须在子线程执行,而Android的开发规范规定我们不能在子线程中访问UI控件,否则会触发程序异常,而Handler 就是为了解决在子线程中访问UI的这个问题而诞生的。
1、问题:为什么Android 的UI线程(主线程)是线程不安全的?为什么Android 采用单线程模型来处理UI操作?
答:android UI 中是由invalidate()来更新界面,而invalidate()方法是线程不安全。
详解:
更新UI只能是主线程的工作,子线程更新UI是线程不安全的,所以android里非主线程操作主UI就会报错。这是因为多线程中并发访问可能会导致UI处于不可预期的状态,即子线程可以有好多个,但如果每个子线程都直接对UI元素进行操作,界面会混乱不堪(例如多个线程同时操作一个控件可能会有冲突发生,控件不知道该执行哪一个的命令)。
单线程模型:线程会面临安全问题,虽然可以通过加锁机制来解决线程的安全问题,但是加锁首先会使UI访问的逻辑变得复杂,其次降低运行效率,鉴于这两个缺点,最简单且高效的做法就是采用单线程模型来处理UI操作,所以主线程(UI线程)并没进行加锁限制多线程访问, 可能这就是“出于性能优化考虑”。
2、问题:既然没有对多线程访问进行限制,而且子线程依然有进行UI操作的需求,那么该如何解决呢?
所以Android规定只能在主线程中进行UI元素的更改,即所有子线程如果要修改用户界面,就必须先通知我(主线程),我来帮你们完成 。所以 android 的 UI 操作一定要在 UI 线程中执行。
Android的单线程模型有两条原则:
1.不要阻塞UI线程。
2.不要在UI线程之外访问Android UI 控件
拓展:
3、问题:Android是怎么知道你是不是在子线程中访问UI的?
答:ViewRootImpl 对UI 的操作进行了验证,这个验证是通过ViewRootImpl 的checkThread 方法来完成的,如下所示:
void checkThread(){
if(mThread!=Thread.currentThread()){
throw new CalledFromWrongThreadException("Only the original thread that created a view hierarchy can
touch its views.");
}
}
前面介绍完 Handler 的由来和 Android 的UI 线程,现在开始我们的正菜,详解Handler 机制:
Handler 是什么?
Handler 是Android 消息机制的上层接口,它的主要作用是将一个任务切换到某个指定的线程中去执行,是为了解决子线程中无法访问UI的问题而设计的。说白了它就是一个传递消息、处理消息的工具,它和它的两个兄弟 MessageQueue、Looper 齐心协力才能实现上述的功能。
Android 的消息机制主要是指 Handler 的运行机制和Handler所附带的MessageQueue和Looper的工作过程,Handler 的运行需要底层的 MessageQueue(消息队列)和Looper 的支撑。
Handler、Message、MessageQueue、Looper 之间的关系
1. Message(消息的载体)
Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。上一小节中我们使用到了Message的what字段,除此之外还可以使用arg1和arg2字段来携带一些整型数据,使用obj字段携带一个Object对象。
2. Handler(消息的消费者,即发送和处理)
Handler顾名思义也就是处理者的意思,它主要是用于发送和处理消息的。发送消息一般是使用Handler的sendMessage()方法,而发出的消息经过一系列地辗转处理后,最终会传递到Handler的handleMessage()方法中,最终存储在MessageQueue中。Handler 的主要作用就是将一个任务切换到某个指定的线程中去执行。是为了解决子线程中无法访问UI 的问题。
3. MessageQueue(消息的存储器)
MessageQueue是消息队列的意思,它采用单链表的数据结构来存储消息列表。它主要用于存放所有通过Handler发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue对象。
4. Looper(消息的处理器)
Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当发现MessageQueue中存在一条消息,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中也只会有一个Looper对象。
打个比方:传送带传送物品,Looper就是传送带的电机,它会无限的循环查询传送带MessageQueue中存储的物品,Message就是存储消息的物品,由Handler在上游发送(sendMessage),也由Handler在下游取出消费(handleMessage)
拓展:Handler 如何获取到当前线程的Looper?
ThreadLocal 可以在不同的线程中互不干扰的存储并提供数据,通过ThreadLocal 可以轻松的获取到每个线程的Looper,线程默认是没有Looper的,如果需要使用Handler就必须为线程创建Looper。主线程(即UI 线程)就是ActivityThread,ActivityThread 在被创建时就会初始化Looper,者也是在主线程中默认可以使用Handler 的原因。
Handler 的工作原理:Handler 创建时会采用当前线程的Looper来构建内部的消息循环系统,如果当前线程没有Looper,那么就会报错,如下所示:
E/AndroidRuntime: FATAL EXCEPTION: Thread-50003
Process: com.example.cyf.myapplication, PID: 2223
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
at com.example.cyf.myapplication.MainActivity$3$1.<init>(MainActivity.java:0)
at com.example.cyf.myapplication.MainActivity$3.run(MainActivity.java:56)
at java.lang.Thread.run(Thread.java:818)
怎么解决:
1、为当前线程创建一个Looper,一个线程只能有一个Looper 对象 ,
2、在一个有Looper 的线程中创建 Handler
Handler 创建完毕后,通过Handler 的post 方法将一个 Runnable 投递到Handler 内部的Looper 中去处理(最终也是通过 send 方法来完成的),也可以通过 Handler 的 send 方法发送一个消息,这个消息同样会在 Looper中处理。当Handler 的send 方法被调用时,他会调用MessageQueue 的 enqueueMessage 方法将这个消息放入消息队列中,然后Looper 发现有新消息到来时,就会处理这个消息,最终消息中的Runnable 或者Handler 的 handleMessage 方法就会被调用,注意Looper 是运行在创建Handler所在的线程中的
MessageQueue 消息队列的工作原理:
其主要包含两个操作:插入和读取(读取本身会伴随着删除操作),其分别对应着 enqueueMessage 和next 方法,其中enqueueMessage 方法的作用是向消息队列中插入一条消息,而next 的作用是从消息队列中取出一条消息并将其从消息队列中删除。
MessageQueue 是通过一个单链表的数据结构来维护消息队列的,单链表在插入和删除上比较有优势。
MessageQueue 的enqueueMessage 方法:
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
其主要实现单链表的插入操作
MessageQueue 的next 方法:
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {//无限循环
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message. 获取消息
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null; //删除操作
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;//返回消息,跳出循环
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {//退出消息队列直接返回null,跳出循环
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
从上可以看出 next 方法是一个无限循环方法,如果消息队列中没有消息,则next 方法会一直阻塞在这里,当有新消息到来时,next 方法会返回这条消息,并将其从单链表中删除。
Looper 的工作原理:
在Android 消息机制中扮演者消息循环的角色,就是不停地从MessageQueue 中查看是否有新的消息,如果有就立即处理,没有则一直阻塞在哪里,在Looper 的构造方法中,会创建一个 MessageQueue 消息队列,并将当前的线程保存起来,其源码如下:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Handler 的工作需要Looper,没有Looper的线程就会报错,Looper的创建通过 Looper.prepare() 为当前线程创建一个Looper,通过Looper.loop() 开启消息循环。如下所示:
new Thread("Thread#2"){
@Override
public void run() {
Looper.prepare();//为Thread#2 构建Looper,在该方法中,会将当前线程的Looper 存储在ThreadLocal 中
//为Thread#2 构建Handler,Handler 中会通过 mLooper = Looper.myLooper(); 获取当前线程的Looper
Handler handler = new Handler();
Looper.loop();//开启Looper 消息循环
}
}.start();
Looper 还可通过prepareMainLooper 方法构建Looper,该方法主要是给主线程(ActivityThread) 创建Looper使用,其本质也是通过prepar 方法来实现的,由于主线程的Looper 比较特殊,故Looper 提供了一个 getMainLooper 方法,通过它可在任何地方获取到主线程的Looper。
Looper的退出:
1、通过quit 方法退出Looper,该方法会直接退出Looper
2、通过quitSafely 方法退出Looper,quitSafely 只是设定了一个退出标记,然后把消息队列中的已有的消息处理完毕后才安全的退出
Looper 的 quit 和 quitSafely 方法:
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
MessageQueue 的 quit 方法
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;//退出状态标志位
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
只有当Looper 的quit 或者quitSafely 方法被调用时,Looper 就会调用MessageQueue 的quit 方法来通知消息队列退出,当消息队列被标记为退出状态时,会跳出 next 方法的死循环并返回null,MessageQueue 的next 方法就会返回 null,就会跳出loop 方法的死循环。即Looper 必须退出,否则looper 方法会一直循环下去。
Looper 退出后,通过Handler 发送的消息会失败,此时Handler 的send 方法会返回 false。在子线程中如果手动为其创建Looper,那么在所有的事情完成以后应该调用quit 方法来终止消息循环,否则这个子线程就会一直处于等待的状态,如果退出Looper 后,这个线程就会立刻被终止,因此建议不需要的时候终止Looper。
Looper 最重要的一个方法是loop 方法,只有调用了loop 后,消息循环系统才会真正的其作用,它的实现如下所示:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the 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;
// 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 获取消息队列中的消息
if (msg == null) {//如果消息为null, 即消息队列已退出,loop退出循环,
// 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
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
//处理消息 msg.target 在Handler 的enqueueMessage 方法中被赋值为发送消息的handler对象,即调用handler 的dispatchMessage方法
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (slowDispatchThresholdMs > 0) {
final long time = end - start;
if (time > slowDispatchThresholdMs) {
Slog.w(TAG, "Dispatch took " + time + "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);
}
// 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();
}
}
从上可知以下2点:
loop 方法会调用 MessageQueue 的 next 方法来获取新的消息,当没有消息时,next 方法会阻塞在哪里,从而导致looper 方法阻塞在哪里,如果MessageQueue 的 next 方法返回了新消息,Looper 就会通过 msg.target.dispatchMessage(msg) 处理这条消息,这里的msg.target 是发送这条消息的 Handler 对象,这样 Handler 发送的消息最终又交给他的 dispatchMessage方法来处理了,但这里的 Handler 的dispatchMessage 方法是在创建 Handler 时 所使用的Looper 中执行的,这样就成功的将代码逻辑切换到指定的线程中去执行了
public final class Looper {
private static final String TAG = "Looper";
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
private Printer mLogging;
public static void prepare() {
prepare(true);
}
//创建一个 Looper 对象,并存储在当前线程的ThreadLocal 中
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));
}
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the 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;
// 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
if (msg == null) {//当msg 为空时,退出
// 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 在Handler 的enqueueMessage 方法中被赋值为发送消息的handler对象,即调用handler 的dispatchMessage方法
msg.target.dispatchMessage(msg);
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();
}
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
//从ThreadLocal 中获取当前线程存储的 Looper 对象
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
/**
* Return the {@link MessageQueue} object associated with the current
* thread. This must be called from a thread running a Looper, or a
* NullPointerException will be thrown.
*/
public static @NonNull MessageQueue myQueue() {
return myLooper().mQueue;
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);//创建一个 MessageQueue 消息队列
mThread = Thread.currentThread();//将当前的线程保存起来
}
/**
* Returns true if the current thread is this looper's thread.
*/
public boolean isCurrentThread() {
return Thread.currentThread() == mThread;
}
/**
* Control logging of messages as they are processed by this Looper. If
* enabled, a log message will be written to <var>printer</var>
* at the beginning and ending of each message dispatch, identifying the
* target Handler and message contents.
*
* @param printer A Printer object that will receive log messages, or
* null to disable message logging.
*/
public void setMessageLogging(@Nullable Printer printer) {
mLogging = printer;
}
/**
* Quits the looper.
* <p>
* Causes the {@link #loop} method to terminate without processing any
* more messages in the message queue.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p class="note">
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
* </p>
*
* @see #quitSafely
*/
public void quit() {
mQueue.quit(false);
}
/**
* Quits the looper safely.
* <p>
* Causes the {@link #loop} method to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* However pending delayed messages with due times in the future will not be
* delivered before the loop terminates.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p>
*/
public void quitSafely() {
mQueue.quit(true);
}
/**
* Gets the Thread associated with this Looper.
*
* @return The looper's thread.
*/
public @NonNull Thread getThread() {
return mThread;
}
/**
* Gets this looper's message queue.
*
* @return The looper's message queue.
*/
public @NonNull MessageQueue getQueue() {
return mQueue;
}
/**
* Dumps the state of the looper for debugging purposes.
*
* @param pw A printer to receive the contents of the dump.
* @param prefix A prefix to prepend to each line which is printed.
*/
public void dump(@NonNull Printer pw, @NonNull String prefix) {
pw.println(prefix + toString());
mQueue.dump(pw, prefix + " ");
}
@Override
public String toString() {
return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
+ ") {" + Integer.toHexString(System.identityHashCode(this)) + "}";
}
}
Handler 的工作原理:
Handler 的主要工作包含消息的发送和接收过程。消息的发送可以通过post 的一些列方法及send 的一系列方法来实现,post 的一系列方法最终也是通过send 的一系列方法来实现的,发送一条消息的典型过程如下所示:
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;//将发送消息的Handler 赋值给 msg.target
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);//调用 MessageQueue 的enqueueMessage 方法插入一条消息
}
post 方法:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;//将 Runnable 对象赋值给 m.callback
return m;
}
从上可以发现,Handler 发送消息的过程仅仅是向消息队列中插入了一条消息,并将发送消息的Handler 赋值给 msg.target,MessageQueue 的next 方法就会返回这条消息给Looper,Looper 接收到消息后就开始处理了,最终消息由 Looper 交给 Handler 处理,即Handler 的 dispatchMessage 方法会被调用,这时 Handler就进入了处理消息的阶段,dispatchMessage 的实现如下所示:
final Callback mCallback;
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Handler 处理消息的过程如下:
首先,检查Message 的 callback 是否为 null, 不为null 就通过 handlerCallback来处理消息,Message 的callback 是一个 Ruannable 对象,实际上就是 Handler 的post 方法所传递的 Runnable 参数, handlerCallback 的逻辑如下所示:
private static void handleCallback(Message message) {
message.callback.run();
}
其次检查mCallback 是否为 null,不null 就调用 mCallback 的 handlerMessage 方法来处理消息。Callback 是一个接口,其定义如下:
通过 Callback 可以通过如下方式来创建 Handler 对象:
Handler handler = new Handler(callback);
Callback 的意义就是可以用来创建一个Handler的实例但不需要派生Handler 的子类,在日常开发中,创建Handler 的最常见的方式就是派生一个Handler 的子类并重写其 handlerMessage 方法来处理具体的消息,当我们不想派生子类时,就可以通过Callback 来实现。最后调用Handler 的handleMessage 方法来处理消息。
Handler 处理消息的过程可以归纳为一个流程图,如下所示:
Handler 还有一个特殊的构造方法,可以通过一个特定的 Looper 来构造 Handler,它的实现如下:
public Handler(Looper looper) {
this(looper, null, false);
}
Handler 的默认构造方法如下:
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();
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;
}
很明显,如果当前线程没有Looper 则会抛出"Can't create handler inside thread that has not called Looper.prepare()" 这个异常,即没有Looper在子线程中构建Handler 会报错的原因
Handler 的完整源码如下:
public class Handler {
/*
* Set this flag to true to detect anonymous, local or member classes
* that extend this Handler class and that are not static. These kind
* of classes can potentially create leaks.
*/
private static final boolean FIND_POTENTIAL_LEAKS = false;
private static final String TAG = "Handler";
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
public interface Callback {
public boolean handleMessage(Message msg);
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler() {
this(null, false);
}
/**
* Constructor associates this handler with the {@link Looper} for the
* current thread and takes a callback interface in which you can handle
* messages.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*
* @param callback The callback interface in which to handle messages, or null.
*/
public Handler(Callback callback) {
this(callback, false);
}
/**
* Use the provided {@link Looper} instead of the default one.
*
* @param looper The looper, must not be null.
*/
public Handler(Looper looper) {
this(looper, null, false);
}
/**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages.
*
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
*/
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
/**
* Use the {@link Looper} for the current thread
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(boolean async) {
this(null, async);
}
/**
* Use the {@link Looper} for the current thread with the specified callback interface
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
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;
}
/**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages. Also set whether the handler
* should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
/**
* Returns a string representing the name of the specified message.
* The default implementation will either return the class name of the
* message callback if any, or the hexadecimal representation of the
* message "what" field.
*
* @param message The message whose name is being queried
*/
public String getMessageName(Message message) {
if (message.callback != null) {
return message.callback.getClass().getName();
}
return "0x" + Integer.toHexString(message.what);
}
/**
* Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
* creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
* If you don't want that facility, just call Message.obtain() instead.
*/
public final Message obtainMessage()
{
return Message.obtain(this);
}
/**
* Same as {@link #obtainMessage()}, except that it also sets the what member of the returned Message.
*
* @param what Value to assign to the returned Message.what field.
* @return A Message from the global message pool.
*/
public final Message obtainMessage(int what)
{
return Message.obtain(this, what);
}
/**
*
* Same as {@link #obtainMessage()}, except that it also sets the what and obj members
* of the returned Message.
*
* @param what Value to assign to the returned Message.what field.
* @param obj Value to assign to the returned Message.obj field.
* @return A Message from the global message pool.
*/
public final Message obtainMessage(int what, Object obj)
{
return Message.obtain(this, what, obj);
}
/**
*
* Same as {@link #obtainMessage()}, except that it also sets the what, arg1 and arg2 members of the returned
* Message.
* @param what Value to assign to the returned Message.what field.
* @param arg1 Value to assign to the returned Message.arg1 field.
* @param arg2 Value to assign to the returned Message.arg2 field.
* @return A Message from the global message pool.
*/
public final Message obtainMessage(int what, int arg1, int arg2)
{
return Message.obtain(this, what, arg1, arg2);
}
/**
*
* Same as {@link #obtainMessage()}, except that it also sets the what, obj, arg1,and arg2 values on the
* returned Message.
* @param what Value to assign to the returned Message.what field.
* @param arg1 Value to assign to the returned Message.arg1 field.
* @param arg2 Value to assign to the returned Message.arg2 field.
* @param obj Value to assign to the returned Message.obj field.
* @return A Message from the global message pool.
*/
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
return Message.obtain(this, what, arg1, arg2, obj);
}
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
/**
* Causes the Runnable r to be added to the message queue, to be run
* at a specific time given by <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
* The runnable will be run on the thread to which this handler is attached.
*
* @param r The Runnable that will be executed.
* @param uptimeMillis The absolute time at which the callback should run,
* using the {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
/**
* Causes the Runnable r to be added to the message queue, to be run
* at a specific time given by <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
* The runnable will be run on the thread to which this handler is attached.
*
* @param r The Runnable that will be executed.
* @param uptimeMillis The absolute time at which the callback should run,
* using the {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*
* @see android.os.SystemClock#uptimeMillis
*/
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
/**
* Causes the Runnable r to be added to the message queue, to be run
* after the specified amount of time elapses.
* The runnable will be run on the thread to which this handler
* is attached.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
*
* @param r The Runnable that will be executed.
* @param delayMillis The delay (in milliseconds) until the Runnable
* will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed --
* if the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
/**
* Posts a message to an object that implements Runnable.
* Causes the Runnable r to executed on the next iteration through the
* message queue. The runnable will be run on the thread to which this
* handler is attached.
* <b>This method is only for use in very special circumstances -- it
* can easily starve the message queue, cause ordering problems, or have
* other unexpected side-effects.</b>
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean postAtFrontOfQueue(Runnable r)
{
return sendMessageAtFrontOfQueue(getPostMessage(r));
}
/**
* Runs the specified task synchronously.
* <p>
* If the current thread is the same as the handler thread, then the runnable
* runs immediately without being enqueued. Otherwise, posts the runnable
* to the handler and waits for it to complete before returning.
* </p><p>
* This method is dangerous! Improper use can result in deadlocks.
* Never call this method while any locks are held or use it in a
* possibly re-entrant manner.
* </p><p>
* This method is occasionally useful in situations where a background thread
* must synchronously await completion of a task that must run on the
* handler's thread. However, this problem is often a symptom of bad design.
* Consider improving the design (if possible) before resorting to this method.
* </p><p>
* One example of where you might want to use this method is when you just
* set up a Handler thread and need to perform some initialization steps on
* it before continuing execution.
* </p><p>
* If timeout occurs then this method returns <code>false</code> but the runnable
* will remain posted on the handler and may already be in progress or
* complete at a later time.
* </p><p>
* When using this method, be sure to use {@link Looper#quitSafely} when
* quitting the looper. Otherwise {@link #runWithScissors} may hang indefinitely.
* (TODO: We should fix this by making MessageQueue aware of blocking runnables.)
* </p>
*
* @param r The Runnable that will be executed synchronously.
* @param timeout The timeout in milliseconds, or 0 to wait indefinitely.
*
* @return Returns true if the Runnable was successfully executed.
* Returns false on failure, usually because the
* looper processing the message queue is exiting.
*
* @hide This method is prone to abuse and should probably not be in the API.
* If we ever do make it part of the API, we might want to rename it to something
* less funny like runUnsafe().
*/
public final boolean runWithScissors(final Runnable r, long timeout) {
if (r == null) {
throw new IllegalArgumentException("runnable must not be null");
}
if (timeout < 0) {
throw new IllegalArgumentException("timeout must be non-negative");
}
if (Looper.myLooper() == mLooper) {
r.run();
return true;
}
BlockingRunnable br = new BlockingRunnable(r);
return br.postAndWait(this, timeout);
}
/**
* Remove any pending posts of Runnable r that are in the message queue.
*/
public final void removeCallbacks(Runnable r)
{
mQueue.removeMessages(this, r, null);
}
/**
* Remove any pending posts of Runnable <var>r</var> with Object
* <var>token</var> that are in the message queue. If <var>token</var> is null,
* all callbacks will be removed.
*/
public final void removeCallbacks(Runnable r, Object token)
{
mQueue.removeMessages(this, r, token);
}
/**
* Pushes a message onto the end of the message queue after all pending messages
* before the current time. It will be received in {@link #handleMessage},
* in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
/**
* Sends a Message containing only the what value.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
/**
* Sends a Message containing only the what value, to be delivered
* after the specified amount of time elapses.
* @see #sendMessageDelayed(android.os.Message, long)
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
/**
* Sends a Message containing only the what value, to be delivered
* at a specific time.
* @see #sendMessageAtTime(android.os.Message, long)
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
/**
* Enqueue a message into the message queue after all pending messages
* before (current time + delayMillis). You will receive it in
* {@link #handleMessage}, in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
/**
* Enqueue a message into the message queue after all pending messages
* before the absolute time (in milliseconds) <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
* You will receive it in {@link #handleMessage}, in the thread attached
* to this handler.
*
* @param uptimeMillis The absolute time at which the message should be
* delivered, using the
* {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
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);
}
/**
* Enqueue a message at the front of the message queue, to be processed on
* the next iteration of the message loop. You will receive it in
* {@link #handleMessage}, in the thread attached to this handler.
* <b>This method is only for use in very special circumstances -- it
* can easily starve the message queue, cause ordering problems, or have
* other unexpected side-effects.</b>
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendMessageAtFrontOfQueue(Message msg) {
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, 0);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
/**
* Remove any pending posts of messages with code 'what' that are in the
* message queue.
*/
public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
}
/**
* Remove any pending posts of messages with code 'what' and whose obj is
* 'object' that are in the message queue. If <var>object</var> is null,
* all messages will be removed.
*/
public final void removeMessages(int what, Object object) {
mQueue.removeMessages(this, what, object);
}
/**
* Remove any pending posts of callbacks and sent messages whose
* <var>obj</var> is <var>token</var>. If <var>token</var> is null,
* all callbacks and messages will be removed.
*/
public final void removeCallbacksAndMessages(Object token) {
mQueue.removeCallbacksAndMessages(this, token);
}
/**
* Check if there are any pending posts of messages with code 'what' in
* the message queue.
*/
public final boolean hasMessages(int what) {
return mQueue.hasMessages(this, what, null);
}
/**
* Check if there are any pending posts of messages with code 'what' and
* whose obj is 'object' in the message queue.
*/
public final boolean hasMessages(int what, Object object) {
return mQueue.hasMessages(this, what, object);
}
/**
* Check if there are any pending posts of messages with callback r in
* the message queue.
*
* @hide
*/
public final boolean hasCallbacks(Runnable r) {
return mQueue.hasMessages(this, r, null);
}
// if we can get rid of this method, the handler need not remember its loop
// we could instead export a getMessageQueue() method...
public final Looper getLooper() {
return mLooper;
}
public final void dump(Printer pw, String prefix) {
pw.println(prefix + this + " @ " + SystemClock.uptimeMillis());
if (mLooper == null) {
pw.println(prefix + "looper uninitialized");
} else {
mLooper.dump(pw, prefix + " ");
}
}
@Override
public String toString() {
return "Handler (" + getClass().getName() + ") {"
+ Integer.toHexString(System.identityHashCode(this))
+ "}";
}
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
private static void handleCallback(Message message) {
message.callback.run();
}
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
final boolean mAsynchronous;
IMessenger mMessenger;
private static final class BlockingRunnable implements Runnable {
private final Runnable mTask;
private boolean mDone;
public BlockingRunnable(Runnable task) {
mTask = task;
}
@Override
public void run() {
try {
mTask.run();
} finally {
synchronized (this) {
mDone = true;
notifyAll();
}
}
}
public boolean postAndWait(Handler handler, long timeout) {
if (!handler.post(this)) {
return false;
}
synchronized (this) {
if (timeout > 0) {
final long expirationTime = SystemClock.uptimeMillis() + timeout;
while (!mDone) {
long delay = expirationTime - SystemClock.uptimeMillis();
if (delay <= 0) {
return false; // timeout
}
try {
wait(delay);
} catch (InterruptedException ex) {
}
}
} else {
while (!mDone) {
try {
wait();
} catch (InterruptedException ex) {
}
}
}
}
return true;
}
}
}
主线程的消息循环:
Android 的主线程就是ActivityThread,主线程的入口方法为 main,在main 方法中系统会通过 Looper.preparMainLooper() 来创建主线程的Looper 记忆MessageQueue,并通过Looper.loop() 来开启主线程的消息循环,过程如下所示:
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
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");
}
主线程的消息循环开始以后,ActivityThread 还需要一个Handler来和消息队列进行交互,这个Handler 就是ActivityThread.H,它的内部定义了一组消息类型,主要包含了四大组件的启动和停止等过程,如下所示:
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100;
public static final int PAUSE_ACTIVITY = 101;
public static final int PAUSE_ACTIVITY_FINISHING= 102;
public static final int STOP_ACTIVITY_SHOW = 103;
public static final int STOP_ACTIVITY_HIDE = 104;
public static final int SHOW_WINDOW = 105;
public static final int HIDE_WINDOW = 106;
public static final int RESUME_ACTIVITY = 107;
public static final int SEND_RESULT = 108;
public static final int DESTROY_ACTIVITY = 109;
public static final int BIND_APPLICATION = 110;
public static final int EXIT_APPLICATION = 111;
public static final int NEW_INTENT = 112;
public static final int RECEIVER = 113;
public static final int CREATE_SERVICE = 114;
public static final int SERVICE_ARGS = 115;
public static final int STOP_SERVICE = 116;
...
}
ActivityThread 通过 ApplicationThread 和AMS 进行进程间通信,AMS 以进程间通信的方式完成 ActivityThread 的请求后会回调 ApplicationThread 中的Binder 方法,然后 ApplicationThread 会向 H 发送消息,H收到消息后会将ApplicationThread 中的逻辑切换到 ActivityThread 中去执行,即切换到主线程中去执行,这个过程就是主线程的消息循环模型。
总结:
1、创建Handler 时,会优先检查是否有Looper,如果没有则抛出异常,由于主线程即ActivityThread 在创建时就构建了Looper(通过Looper.prepareMainLooper 构建),所以在主线程中构建Handler 不会抛异常,如果在子线程中,在构建Handler 之前必须先创建Looper (通过Looper.preparLooper 创建),创建好Handler 后,还需启动Looper。
2、构建Looper 时,会创建一个 MessageQueue ,并将该Looper 存储在当前线程的 ThreadLocal 中,通过 Looper.looper 开启轮询,不停的查找 MessageQueue 中的消息,如果存在未处理的消息,则通过 Message 中的 tag 获取关联的 Handler,并调用 Handler.dispatchMessage 方法处理消息,该方法会最终调用 handlerMessage 方法或者Runable 中 的方法处理消息。
3、Handler 通过 sendMessage 或者 post 方法发送消息,首先会将自己赋值给 Message 的tag,并调用MessageQueue 中的enqueueMessage 方法向MessageQueue 中插入一条消息,Looper 通过MessageQueue 的next 方法获取MessageQueue 中的消息,获取后并将之从 MessageQueue 中删除,如果 MessageQueue 中没有消息,则MessageQueue 、Looper 都会被阻塞挂起。