Android消息机制学习记录
Android消息机制学习记录
一、概述
Android消息机制主要指Handler的运行机制以及Handler
附带的MessageQueue
和Looper
的工作过程,从开发的角度来说Handler是Android消息机制的上层接口,Handler的主要作用是将一个任务切换到某个指定的线程中执行。
Android规定访问UI
只能在主线程中进行,但又不建议在主线程中执行耗时操作,否则会导致程序无法响应即ANR。
1.1 消息机制模型
类名 | 作用 |
---|---|
Message | 消息的载体:用于线程之间传递信息,在不同的线程间交换数据,what,arg12,obj字段可以携带信息。 |
MessageQueue | 存放Handler发送的消息,投递消息(MessageQueue.enqueueMessage)和取走消息队列的消息(MessageQueue.next);每个线程中只有一个MessageQueue对象 |
Handler | 向消息队列发送各种消息事件和处理消息 |
Looper | 每个线程中MessageQueue的管家,调用Looper的loop()方法之后,就会进入到一个无限循环中,每当发现MessageQueue中存在一条消息,就会将他取出,并传递到Handler的handleMessage() |
1.2 Handler的工作原理
Handler创建时会采用当前线程的Looper
构建内部的消息循环系统,如果当前线程没有Looper就会报错。因此,必须在有Looper
的线程中创建Handler。
Handler通过post方法将一个Runnable投递到Handler内部的Looper中处理,也可以通过send方法发送消息,post方法最终也通过send方法完成。这条消息会被添加到MessageQueue
中等待被处理,而Looper则会一直尝试从MessageQueue中取出待处理的信息,最后分发回Handler
的handleMessage()
方法中。Looper运行在创建Handler的线程中,因此运行创建Handler线程的handerMessage()
方法。
Looper通过loop(),不断提取出达到触发条件的Message,并将Message交给target来处理。
小结
- 为什么不允许在子线程中访问UI?
因为Android的UI控件不是线程安全的,如果多线程并发访问可能导致UI控件处于不可预期状态。
- 为什么不对UI控件的访问加上锁机制?
因为锁机制会阻塞某些线程的执行,加上锁机制会让UI访问的逻辑变得复杂,会降低UI访问的效率。
二、Android消息机制分析
2.1 ThreadLocal
ThreadLocal是一个线程内部的数据存储类(Thread Local Storage),通过它可以在指定的线程中存储数据,数据存储以后,只有在指定的线程中可以获取到存储的数据,其他线程无法获取。
ThreadLocal使用场景
一般来说,当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal。Looper、ActivityThread以及AMS中都用到了ThreadLocal。不同线程具有不同Looper,当Handler需要获取线程的Looper时,就可以用ThreadLocal。
**ThreadLocal另一个使用场景是复杂逻辑下的对象传递,**采用ThreadLocal可以让监听器作为线程内的全局对象存在,在线程内通过get方法就能获取到监听器。
- 将监听器通过参数的形式在函数调用栈中传递会让程序设计很糟糕。
- 将监听器作为静态变量供线程访问不具有可扩充性,比如10个线程执行就需要10个静态监听器对象。
ThreadLocal的内部实现:
在不同线程访问同一个ThreadLocal对象,获取到的值可以不一样,即在不同线程中维护一套数据的副本且彼此互不干扰。因为其有一个ThreadLocalMap静态内部类。而我们使用的 get()、set() 方法都是调用了这个ThreadLocalMap类对应的 get()、set() 方法。
ThreadLocalMap以ThreadLocal为KEY,设置的VALUE为值。
set(T value)
将value存储到当前线程的线程内部存储区域(ThreadLocalStorage),源码如下:
public void set(T value) {
Thread t = Thread.currentThread(); //获取当前线程
ThreadLocalMap map = getMap(t); //查找当前线程的本地储存区
if (map != null)
map.set(this, value);//保存数据value到当前线程
else
//当线程本地存储区,尚未存储该线程相关信息时,
//创建ThreadLocalMap本地存储区对象
createMap(t, value);
}
// ThreadLocalMap.set
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
set() 不像 get() 那样使用快速路径,因为使用 set() 创建新条目与替换现有条目一样普遍,
在这种情况下,快速路径往往会失败.
// We don't use a fast path as with get() because it is at least as common to use set() to create new entries as it is to replace existing ones, in which case, a fast path would fail more often than not.
get( )
获取当前线程的线程内部存储区域(ThreadLocalStorage)的数据,源码如下:
public T get() {
Thread t = Thread.currentThread();//获取当前线程
ThreadLocalMap map = getMap(t);//查找当前线程的本地储存区
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);//获取当前线程的本地储存区中的Entry
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;//返回当前线程储存区中的数据
}
}
return setInitialValue();
}
ThreadLocalMap.Entry:
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
2.2 MessageQueue
MessageQueue内部不是队列,而是插入和删除有优势的单链表。MessageQueue是消息机制的Java层和C++层的连接纽带,大部分核心方法都交给native层来处理,其中MessageQueue类中涉及的native方法如下:
private native static long nativeInit();
private native static void nativeDestroy(long ptr);
private native void nativePollOnce(long ptr, int timeoutMillis);
private native static void nativeWake(long ptr);
private native static boolean nativeIsPolling(long ptr);
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
boolean enqueueMessage(Message msg, long when)
往消息队列中插入一条信息
boolean enqueueMessage(Message msg, long when) {
// 每一个普通Message必须有一个target
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) {//正在退出时,回收msg,加入到消息池
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) {
//p为null(代表MessageQueue没有消息) 或者msg的触发时间是队列中最早的, 则进入该该分支
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
//将消息按时间顺序插入到MessageQueue。一般地,不需要唤醒事件队列,除非
//消息队头存在barrier,并且同时Message是队列中最早的异步消息。
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;
}
//消息没有退出,我们认为此时mPtr != 0
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
enqueueMessage的实现来看,主要操作其实就是单链表的插入操作,这里就不再过多解释了,
Message 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
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//阻塞操作,当等待nextPollTimeoutMillis时长,或者消息队列被唤醒,都会返回
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;
//当消息的Handler为空时,则查询异步消息
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);
//设置消息的使用状态,即flags |= FLAG_IN_USE
msg.markInUse();
return msg;//成功地获取MessageQueue中的下一条即将要执行的消息
}
} else {
//没有消息
// No more messages.
nextPollTimeoutMillis = -1;
}
//消息正在退出,返回null
// Process the quit message now that all pending messages have been handled.
处理完所有待处理的消息后处理退出消息。
if (mQuitting) {
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.
如果第一次空闲,则获取要运行的空闲器的数量。空闲handle仅在队列为空或第一条消息时运行
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
//没有idle handlers 需要运行,则循环并等待。
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
//只有第一次循环时,会运行idle handlers,执行完成后,重置pendingIdleHandlerCount为0.
我们只在第一次迭代期间到达这个代码块
// 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//去掉handler的引用
boolean keep = false;
try {
keep = idler.queueIdle();//idle时执行的方法
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
//重置idle handler个数为0,以保证不会再次重复运行
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
//当调用一个空闲handler时,一个新message能够被分发,因此无需等待可以直接查询pending message.
// 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方法会返回这条消息并将其从单链表中删除。
2.3 Looper
Looper在Android的消息机制中扮演着消息循环的角色,具体来说,Looper会不停地从MessageQueue
中查看是否有新消息,然后将当前线程的对象保存起来。
Looper(boolean quitAllowed)
在构造方法中它会创建一个MessageQueue即消息队列,然后将当前线程的对象保存起来,如下所示。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);//创建一个MessageQueue
mThread = Thread.currentThread();//将当前线程对象保存起来
}
我们知道,Handler的工作需要Looper,没有Looper的线程就会报错,那么如何为一个线程创建Looper呢?
其实很简单,通过Looper.prepare()即可为当前线程创建一个Looper,接着通过Looper.loop()来开启消息循环:
new Thread("Thread#2") {
@Override
public void run() {
Looper.prepare();
Handler handler = new Handler();
Looper.loop();
};
}.start();
prepare(boolean quitAllowed)
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
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");
}
//创建Looper对象,并保存到当前线程的ThreadLocalStorage区域
sThreadLocal.set(new Looper(quitAllowed));
}
prepareMainLooper()
可以在任何地方获取到主线程的Looper
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
loop()
只有调用了loop方法,消息循环系统才会真正地起作用。
public static void loop() {
final Looper me = myLooper();//获取TLS存储的Looper对象
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();
允许使用系统道具覆盖阈值。例如adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
// Allow overriding a threshold with a system prop. e.g. adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
for (;;) {//进入loop的主循环方法
Message msg = queue.next(); // might block
if (msg == null) {
//没有消息表示消息队列正在退出。
// No message indicates that the message queue is quitting.
return;
}
这必须在局部变量中,以防 UI 事件设置记录器
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;//默认为null,可通过setMessageLogging()方法来指定输出,用于debug功能
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
确保观察者在处理事务时不会改变。
// Make sure the observer won't change while processing a transaction.
final Observer observer = sObserver;
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
Object token = null;
if (observer != null) {
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
msg.target.dispatchMessage(msg);//用于分发Message
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
一旦我们写了一个慢速传递日志,就压制直到队列耗尽。
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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();//将Message放入消息池
}
}
loop方法是一个死循环,唯一跳出循环的方式是MessageQueue
的next
方法返回null。当Looper的quit方法被调用时,Looper
就会调用MeaaageQueue
的quit
或者quitSafely
方法来通知MeaaageQueue
退出,当消息队列被标为退出状态时,它的next
方法就会返回null
,跳出loop循环。
next是一个阻塞操作,当没有消息时,next方法会一直阻塞在那里,这也导致loop方法一直阻塞在那里。如果MessageQueue的next方法返回了新消息,Looper就会处理这条消息:msg.target.dispatchMessage(msg)
,这里的msg.target
是发送这条消息的Handler对象,这样Handler发送的消息最终又交给它的dispatchMessage
方法来处理了。但是这里不同的是,Handler的dispatchMessage
方法是在创建Handler
时所使用的Looper
中执行的,这样就成功地将代码逻辑切换到指定的线程中去执行了。
在Looper的构造方法中会去保存当前的线程,Looper在哪个线程创建,Handler的dispatchMessage方法终究会在那个线程执行。
quit()/quitSafely()
public void quit() {//直接退出Looper
mQueue.quit(false); //消息移除
}
public void quitSafely() {//设定一个标记,然后把消息队列中已有消息处理完后才安全退出
mQueue.quit(true); //安全地消息移除
}
2.4 Handler
Handler的工作主要包含消息的发送和接收过程。消息的发送可以通过post的一系列方法以及send的一系列方法来实现,post的一系列方法最终是通过send的一系列方法来实现的。
Handler(Looper looper)
Handler还有一个特殊的构造方法,那就是通过一个特定的Looper来构造Handler,它的实现如下所示。通过这个构造方法可以实现一些特殊的功能。
/**
* Use the provided {@link Looper} instead of the default one.
使用提供的 {@link Looper} 而不是默认的。
*
* @param looper The looper, must not be null.
@param looper 不能为空。
*/
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
这个构造方法会调用下面的构造方法。
Handler( Callback callback, boolean async)
所有构造方法都调用这个方法。
如果当前线程没有Looper的话,就会抛出“Can’t create handler inside thread that has not called Looper.prepare()”这个异常,这也解释了在没有Looper的子线程中创建Handler会引发程序异常的原因。
public Handler(@Nullable 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());
}
}
//必须先执行Looper.prepare(),才能获取Looper对象,否则为null.
mLooper = Looper.myLooper();//从当前线程的TLS中获取Looper对象
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;//消息队列,来自Looper对象
mCallback = callback;//回调方法
mAsynchronous = async;//设置消息是否为异步处理方式
}
sendMessage(Message msg)
发送一条消息的典型过程如下所示。
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(@NonNull 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(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
sendMessage发送的方法最终会进入到MessageQueue
中,而MessageQueue
的next方法就会返回这条消息给Looper(Looper.loop方法内部调用了MessageQueue的next方法),Looper收到消息后就开始处理了,最终消息由Looper交给Handler处理。即Handler的dispatchMessage方法会调用,这时就进入了处理消息的阶段。
dispatchMessage(Message msg)
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
//检查Message的callback是否为null,不为null(存在回调方法)就通过handleCallback来处理消息。
handleCallback(msg);
} else {
if (mCallback != null) {
//当Handler存在Callback成员变量时,回调方法handleMessage();
if (mCallback.handleMessage(msg)) {
return;
}
}
//Handler自身的回调方法handleMessage()
handleMessage(msg);
}
}
Message的callback是一个Runnable对象,实际上就是Handler的post方法所传递的Runnable参数
。handleCallback的逻辑也是很简单,如下所示
private static void handleCallback(Message message) {
message.callback.run();
}
其次,msg.callback(就是Handler的post方法所传递的Runnable参数)为null,再检查mCallback是否为null,不为null就调用mCallback的handleMessage方法来处理消息。Callback是个接口,它的定义如下:
/**
* Callback interface you can use when instantiating a Handler to avoid
可以在实例化 Handler 时使用的回调接口,以避免必须实现自己的 Handler 子类。
* having to implement your own subclass of Handler.
*
* @param msg A {@link android.os.Message Message} object
@param msg 一个 {@link android.os.Message Message} 对象
* @return True if no further handling is desired
@return 如果不需要进一步处理,则返回 True
*/
public interface Callback {
public boolean handleMessage(Message msg);
}
在日常开发中,创建Handler最常见的方式就是派生一个Handler的子类并重写其handleMessage方法来处理具体的消息,而Callback给我们提供了另外一种使用Handler的方式,当我们不想派生子类时,就可以通过Callback来实现。
Handler处理消息的过程可以归纳为一个流程图:
2.5 主线程的消息循环
Android主线程是ActivityThread,主线程的入口方法是main,main方法中会通过Looper.preapareMainLooper()
创建主线程的Looper
以及MesaageQueue
public static void main(String[] args) {
// 初始化Environment
Environment.initForCurrentUser();
// 初始化Event日志
EventLogger.setReporter(new EventLoggingReporter());
// 根据用户Id创建指定目录
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
// 将当前线程作为主线程,初始化Looper
Looper.prepareMainLooper();
// 创建ActivityThread
ActivityThread thread = new ActivityThread();
// 如果是System则直接创建Application,如果非System则将ApplicationThread注册到AM中
thread.attach(false);//建立Binder通道 (创建新线程)
// 初始化Handler
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
//消息循环运行
Looper.loop();
// 异常终止,注意这里的异常通常是执行不到的,上方loop有异常也不会执行到这里。
throw new RuntimeException("Main thread loop unexpectedly exited");
}
ActivityThread还有一个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
和ActivityManagerService
进行进程间通信,AMS以进程间通信的方式完成ActivityThread
的请求后会回调ApplicationThread
中的Binder
方法,然后ApplicationThread
会向H发送消息,H收到消息后会将ApplicationThread
中的逻辑切换到ActivityThread
中去执行,即切换到主线程中去执行,这个过程就是主线程的消息循环模型。
- system_server进程是系统进程Java FrameWork框架的核心载体,里面运行了大量的系统服务,比如这里提供ApplicationThreadProxy(简称ATP),ActivityManagerService(简称AMS),这个两个服务都运行在system_server进程的不同线程中,由于ATP和AMS都是基于IBinder接口,都是binder线程,binder线程的创建与销毁都是由binder驱动来决定的。
- App进程则是我们常说的应用程序,主线程主要负责Activity/Service等组件的生命周期以及UI相关操作都运行在这个线程; 另外,每个App进程中至少会有两个binder线程 ApplicationThread(是ActivityThread的内部类)和ActivityManagerProxy(它是ActivityManagerNative的内部类),除了图中画的线程,其中还有很多线程,比如signal catcher线程等。