Android消息机制
文章目录
- Android消息机制
- 消息传递与处理的流程(配图示)
- 1.【入口】 在 ActivityThread.class 的 main() 方法,为主线程创建 Looper,并开启 loop() 循环
- 2.【创建Looper】通过 Looper.prepareMainLooper() 创建主线程的 Looper,并将主线程的 Looper 存放在 ThreadLocal 中。
- 3. 【开启loop循环】通过 Looper.loop() 来启动 Looper 的死循环,不断接收 Message消息,可能阻塞。
- 4. 【获取消息】Looper.loop() 的每次循环都需要从 MessageQueue消息队列 中获取消息
- 5. 【消息入队】通过MessageQueue.class的enqueueMessage() 让Message消息入队
- 6.【消息处理】 通过Handler.handleMessage() 来进行Message消息处理
- 7. 【实践】如何使用Handler来处理来自其他线程的消息事件?
- 8. 【常见疑问】为什么Looper.loop()在主线程中死循环不会让程序卡死?
- 9. 【常见疑问】Activity的生命周期如何表现?
- 10.【常见疑问】 和ANR的区别
Android的消息传递机制主要由: Looper, Message, MessageQueue, Handler完成。
Looper
:负责不断获取消息队列中的消息。
MessageQueue
:消息队列,单链表形式存放Message队列
Message
: 消息实体
Handler
: 其中的handleMessage()
用来处理那些交给它处理的消息。也可以通过其中的sendMessage()
来将自定义消息加入到消息队列中。系统中可以有多个Handler,包括系统本身设计的用来处理系统消息的,也包括用户自定义实现的用来处理自定义消息的。
消息传递与处理的流程(配图示)
1.【入口】 在 ActivityThread.class 的 main() 方法,为主线程创建 Looper,并开启 loop() 循环
在ActivityThread中的main()
方法准备Looper。
public static void main(String[] args) {
//initial...
Looper.prepareMainLooper();
//...
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
//...
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
2.【创建Looper】通过 Looper.prepareMainLooper() 创建主线程的 Looper,并将主线程的 Looper 存放在 ThreadLocal 中。
进入 Looper.prepareMainLooper()
之后,就是创建主线程的Looper。
public static void prepareMainLooper() {
//在ThreadLocal中设置主线程Looper
prepare(false);
synchronized (Looper.class) {
//确保在此之前主线程Looper没有任何引用实例
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
//将主线程Looper引用为ThreadLocal中设置的Looper
sMainLooper = myLooper();
}
}
/**
* 1. 确保ThreadLocal中主线程没有设置过Looper
* 2. 在主线程中,调用ThreadLocal的set方法设置Looper
*/
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));
}
其中,上述代码最后一行的 new Looper()
构造函数中,为该 Looper 实例设置了消息队列与对应的当前线程:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
3. 【开启loop循环】通过 Looper.loop() 来启动 Looper 的死循环,不断接收 Message消息,可能阻塞。
将主线程的Looper设置好之后,在ActivityThread.main()
的最后通过 Looper.loop()
开启Looper的死循环。
public static void loop() {
final Looper me = myLooper();
//...
for (;;) {
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
死循环中,每一轮都调用了loopOnce()
,它的主要任务通过:
Message msg = me.mQueue.next();
来从消息队列中获取消息,并加以处理:
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block
if (msg == null) {
// 如果拿到的消息是null了,说明退出了messageQueue,也说明程序结束了。
return false;
}
//...
try {
msg.target.dispatchMessage(msg);
} finally {
}
//...
msg.recycleUnchecked();
return true;
}
4. 【获取消息】Looper.loop() 的每次循环都需要从 MessageQueue消息队列 中获取消息
MessageQueue消息队列是由单链表实现的,它将通过:
Message next(){...}
该 next()
方法获取消息的逻辑:
- 判断是否有消息
- 其次判断是否有人处理该消息
- 消息是否到了处理时机
Message next() {
//空闲的,原先就由系统框架设计好的Handler的个数
int pendingIdleHandlerCount = -1; // -1 only during first iteration
//延迟时间
int nextPollTimeoutMillis = 0;
for (;;) {
//native方法,用于判断是否需要阻塞,
//nextPollTimeoutMillis为-1,将阻塞,
//nextPollTimeoutMillis为0,将跳过,
//nextPollTimeoutMillis为数值,将延迟对应的时间
//若是阻塞,可以在有消息入队时由nativeWake()方法唤醒。
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
//获取消息队头元素
Message msg = mMessages;
if (msg != null && msg.target == null) {
// 如果有消息,但是没有对应处理它的handler,就先跳过它
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
//如果找到了首个有handler可以处理的msg
if (msg != null) {
//但是时间还没到,则设置延迟时间,等到下一个循环开始的时候,阻塞响应时间。
if (now < msg.when) {
// 下一个消息还没准备好。设置一个延迟时间,当它准备好的时候,唤醒。
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
//如果条件都满足,立即取出消息
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;
}
//没有消息的时候,空闲Handles将会运行,如果没有空闲handler,将会设置为阻塞(等待消息入队时被唤醒)。这只会在第一次循环的时候发生。
// 在调用空闲处理程序时,可能已经传递了一条新消息,因此无需等待就可以返回并再次查看挂起的消息
nextPollTimeoutMillis = 0;
}
}
5. 【消息入队】通过MessageQueue.class的enqueueMessage() 让Message消息入队
入队的消息必须有处理它的handler
,(即msg.target
不为空)。
入队的消息根据延迟时间判断是插入队头,还是插入队中首个合适的位置(判断依据:延迟时间)。
这个方法除了通过MessageQueue
本身实例来调用,也可以通过自定义的Handler
的sendMessage()
来间接调用。
boolean enqueueMessage(Message msg, long when) {
//入队的消息必须由处理它的handler
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
synchronized (this) {
//各类错误判断
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
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 {
//是否需要唤醒,要看阻塞状态与队头的消息是否有人处理
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
//将消息msg插入到首个合适的位置
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;
}
//唤醒MessageQueue.next()中的nativePollOnce()
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
6.【消息处理】 通过Handler.handleMessage() 来进行Message消息处理
在 3. 启动Loop 中有这样一段代码:
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block
if (msg == null) {
// 如果拿到的消息是null了,说明退出了messageQueue,也说明程序结束了。
return false;
}
//...
try {
msg.target.dispatchMessage(msg);
} finally {
}
//...
msg.recycleUnchecked();
return true;
}
拿到需要处理的消息msg之后,将会交给 msg.target
也就是对应的处理该msg的handler来处理消息。
这里注意,msg.recycleUnchecked()
方法是msg回收的一个方法,Message中维护着一个sPool,消息池,可以将 Message 实例回收后重复利用。所以当我们需要自定义一个新的 Message 时,推荐使用Message.obtain()
从而获取来自消息池中的 Message 实例,而不是直接new Message()
创建一个新实例。
Handler中处理消息的代码如下,它是待具体实现的:
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(@NonNull Message msg) {
}
/**
* Handle system messages here.
*/
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
7. 【实践】如何使用Handler来处理来自其他线程的消息事件?
下面是一个例子:
public class MainActivity extends AppCompatActivity {
//自定义一个Handler用来处理消息
private Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
Log.e("TAG","msg: "+msg);
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//一个按钮触发发送消息事件
public void click(View view) {
new Thread(()->{
Message message = new Message();
message.what = 1;//这个属于用户自定义TAG,让使用者知道这个msg是关于什么的,或者属于什么分类标签的
handler.sendMessage(message);
}).start();
}
}
handler.sendMessage(msg)
实际就是让message入队,其中的消息队列mQueue
在Handler初始化的时候就在构造方法中拿到了:
public Handler(@Nullable Callback callback, boolean async) {
//...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
//...
}
由handler发起的消息入队调用链如下:
//1. handler.sendMessage
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
//2. 判断延迟时间
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//3. 设置消息的延迟时间
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);
}
//4. 设置msg的属性,并让消息入队
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);
}
8. 【常见疑问】为什么Looper.loop()在主线程中死循环不会让程序卡死?
Android是事件驱动的,在Looper.loop()
调用之前,就通过thread.attach(false)
创建了Binder
线程(具体是指 ApplicationThread
,Binder
的服务端,用于接收系统服务 AMS 发送来的事件).该 Binder 线程通过 Handler 将 Message 发送给主线程。 Binder用于进程间通信。
thread.attach()
中完成AMS与App进程通讯的绑定的代码:
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
这是来自系统服务发来的事件,用于进程间通信。而 ActivityThread 的内部类 H 继承于Handler
,用于同一进程的线程间通信。来自不同地方的消息事件驱动着Android。
9. 【常见疑问】Activity的生命周期如何表现?
Activity的生命周期依靠着主线程的 Looper.loop()
,由 Looper.loop()
不断接收消息事件,再通过 ActivityThread 中的 H.handleMessage(msg)
来处理消息,例如处理 Activity 的请求onCreate
事件。我们关注一下创建 Activity 实例的事件在Handler中是怎么处理的。
class H extends Handler {
//...
public static final int RECEIVER = 113;
//...
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
//...
case RECEIVER: return "RECEIVER";
//...
}
}
return Integer.toString(code);
}
//处理消息
public void handleMessage(Message msg) {
//...
switch (msg.what) {
case RELAUNCH_ACTIVITY:
handleRelaunchActivityLocally((IBinder) msg.obj);
break;
//...
}
//...
}
}
首先 H 的handleMessage()
接收到了 RELAUNCH_ACTIVITY 事件,通过一系列调用;最后调到handleLaunchActivity()
:
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) {
//...
final Activity a = performLaunchActivity(r,customIntent);
if (a != null) {
//...
} else {
//如果创建出错,让activity manager终止。
ActivityClient.getInstance().finishActivity(...);
}
return a;
}
看到其中真正开启 Activity 的是 performLaunchActivity()
:
它首先通过反射构建了一个 Activity,然后通过Instrumentation.callActivityOnCreate()
来主动调用 Activity 的onCreate()
/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
//获取包信息
//...
//获取组件(Activity Service Broadcast ContentProvider)
//...
//创建上下文
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
//通过反射构建activity
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
//...
} catch (Exception e) {
//...
}
//...
synchronized (mResourcesManager) {
//Maps from activity token to local record of running activities in this process
mActivities.put(r.token, r);
}
//...
if(activity != null){
//...
activity.attach(...);
//...
r.activity = activity;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
}
return activity;
}
step1:实例化Activity
由Instrumentation.newActivity()
通过工厂来实例化一个 Activity:
public Activity newActivity(ClassLoader cl, String className,Intent intent) throws InstantiationException, IllegalAccessException,ClassNotFoundException {
String pkg = intent != null && intent.getComponent() != null
? intent.getComponent().getPackageName() : null;
return getFactory(pkg).instantiateActivity(cl, className, intent);
}
其中由AppComponentFactory
来实例化一个Activity:
public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className, @Nullable Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
//通过反射来实例化Activity
return (Activity) cl.loadClass(className).newInstance();
}
step2: 通过Instrumentation调用Activity的onCreate()
public void callActivityOnCreate(Activity activity, Bundle icicle,
PersistableBundle persistentState) {
prePerformCreate(activity);
activity.performCreate(icicle, persistentState);
postPerformCreate(activity);
}
Activity 中的performCreate()
方法,真正调用了 Activity 的 onCreate()
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
//...
if (persistentState != null) {
onCreate(icicle, persistentState);
} else {
onCreate(icicle);
}
//...
//FragmentController的这个方法为FragmentManager提供了一个fragment host(一般这个host是activity)的集成点,该集成点主要是为了提供host(activity)的回调信息。
mFragments.dispatchActivityCreated();
//...
}
10.【常见疑问】 和ANR的区别
ANR: 5s内没有响应输入事件,比如按键、屏幕触摸
ANR本质原因是消息队列中其他消息太耗时,导致按键或者广播消息没有及时处理。
也就是ANR的本质原因不是线程被等待消息入队的阻塞,而是消息队列被其他耗时消息阻塞,导致按键或者广播消息没有及时处理。所以主线程中不推荐进行耗时操作。所以许多数据库框架也都不允许把增删改查操作放在主线程中进行。