首先,我将Handler相关的原理机制形象的描述为以下情景:
Handler:快递员(属于某个快递公司的职员)
Message:包裹(可以放置很多东西的箱子)
MessageQueue:快递分拣中心(分拣快递的传送带)
Looper:快递公司(具有处理包裹去向的管理中心)
情景分析:在子线程中更新主线程的UI
其中的原理机制可以形象的理解为:
某天,你想给朋友寄一件礼物,首先你拿个箱子装好礼物并包裹好,下单叫了某家的快递员上门取件,快递员揽收你的包裹后,会将包裹送往快递分拣中心,等待配送车送出你的包裹。等配送车来了,就按照你的包裹地址信息,送到指定地方站点,然后分派给相应的快递员,将你的包裹送到你的朋友手里。
这整个邮寄包裹的过程可以形象的理解为Handler的工作机制原理,下面还原一下实际工作过程:
某时,你想刷新主界面的TextView,无奈你不在主线程,此时你就会包装好Message,然后声明一个Handler,让Handler将你的Message送往主线程(Looper),Handler将你的Message送到主线程后,还需要排队等待,等轮到你的时候,主线程就会告诉Handler,这个Message可以处理了,你负责分发一下,于是,Handler将该Message分发到相应的回调或者handleMessage( ) 方法中,于是,你就在该方法中更新了UI。
下面,我对这四位大佬一个个进行介绍。
一、Message(消息)
Message.class位于android.os.包中。Message的构造函数为无参构造方法,且只有一个构造方法;
public Message() { }
除了构造方法可以创建实例对象外,还可以通过内部的静态方法来创建:
static Message obtain()
static Message obtain(Message orig)
static Message obtain(Handler h)
static Message obtain(Handler h, Runnable callback)
static Message obtain(Handler h, int what)
static Message obtain(Handler h, int what, Object obj)
static Message obtain(Handler h, int what, int arg1, int arg2)
static Message obtain(Handler h, int what, int arg1, int arg2, Object obj)
以上几个静态的方法里面都会首先调用第一个方法来创建一个Message对象,我们来看看源码(API 28)
public static final Object sPoolSync = new Object(); //同步锁对象
private static Message sPool; //全局池消息实例
/**
* 从全局池返回一个新的消息实例,允许我们在许多情况下避免分配新对象。
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
//......
return m;
}
}
return new Message();
}
如果当前全局池的Message实例不为空,则返回第一个消息实例。所以,大多数情况下,使用obtain()来获得一个Message对象,可以避免消耗更多的内存资源。
对于其他 static obtain( ) 的重载方法,通过源码,可以发现,都是进行赋值操作,没有太多的可讨性。唯一得注意一下的是 obtain(Handler h, Runnable callback)这个静态方法:
/*package*/ Handler target;
/*package*/ Runnable callback;
public static Message obtain(Handler h, Runnable callback) {
Message m = obtain();
m.target = h;
m.callback = callback;
return m;
}
可以看到,也是赋值操作,target是保护级别的成员变量,即只有同包名空间可以访问,此变量意义重大。除了target,还有一个callback,这个callback也是配合着Handler来发挥作用的。后面讲到Handler会解释到,请稍安勿躁。
此时,大家先要记住的就几点:
Message有8个静态方法可以创建Message实例
Message有两个重要的成员变量,分别为target 和callback,一个是Handler,一个是Runnable。
Message有4个公开变量what、arg1、arg2、obj 可以存储消息进行传递
Message还有一个包间成员变量next,它是Message类型,后面会使用到,知道有这个next就行
以上就是Message的基本秘密了,很简单,没有什么复杂的东西(作为一个包裹箱,就是这么简单,能装一些东西,然后附带一些关键信息)。
二、Handler(处理机)
Handler.class也位于android.os包中。Handler英文意思为:处理者,管理者,处理机。它在消息传递过程中扮演着重要的角色,是消息的主要处理者,说白了,就是收消息,最终处理消息(它就像一个快递员,收快递,然后领快递单,派送快递)。
1、Handler的构造方法(API 28)
Handler()
Handler(Callback callback)
Handler(boolean async)
Handler(Callback callback, boolean async)
Handler(Looper looper)
Handler(Looper looper, Callback callback)
Handler(Looper looper, Callback callback, boolean async)
通过源码可以发现,上面的构造方法都是上面一个个往下调用的,第一个调用第二个,第二个调用第三个…所以,我们首先把目光放在最后一个方法上:
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
这是一个赋值的构造方法。再看另外一个构造方法:
public Handler(Callback callback, boolean async) {
//......
mLooper = Looper.myLooper(); //返回与当前线程关联的Looper对象,在后面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对象的消息队列,在后面MessageQueue会讲到
mCallback = callback; //接口回调
mAsynchronous = async; //是否异步
}
public interface Callback {
public boolean handleMessage(Message msg); //这个函数大家都很熟悉了,暂不细说,总之都知道是用来回调消息的
}
整个构造方法的过程中会确立以下几件事:
获取当前Handler实例所在线程的Looper对象:mLooper = Looper.myLooper()
如果Looper不为空,则获取Looper的消息队列,赋值给Handler的成员变量mQueue:mQueue = mLooper.mQueue
可以设置Callback 来处理消息回调:mCallback = callback
Handler是消息的处理者,但是它并不是最终处理消息的那个大佬,它有且只能有一个上级个领导,就是Looper,Handler是将消息上报给Looper(领导),然后排队等待,等Looper(领导)处理完消息了,就会通知Handler去领取消息,给Handler分配任务,Handler拿到消息后在自行往下分发,Handler只能听命与Looper(领导)。
举个实际运用中的情景:
当你需要在子线程中更新主线程的UI时,你就会在当前的Activity下创建一个Handler对象,然后在它的handleMessage() 中更新UI。
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//... 更新UI
}
};
在你创建这个mHandler 实例的时候,底层做了以下几件事情:
1、拿到mHandler所在线程的Looper,当前mHandler是在Activity中创建的,很明显,当前的线程就是主线程,所以 mHandler的成员变量mLooper = Looper.myLooper(),此处就已经将当前的主线程Looper赋值过去了。
2、紧接着,判断mLooper 是否为空,明显不为空,所以又会将主线程的消息队列赋值给mQueue。告诉Handler,你要是有消息,就送到这个消息队列中来,我(Looper)会一个个按顺序处理,处理完后我就会告诉你,你再处理。
由此我们可以得出结论:
1、Handler有且只能绑定一个线程的Looper;
2、Handler的消息是发送给Looper的消息队列MessageQueue,需要等待处理;
所以,如果你在子线程中声明了一个Handler,是不能直接更新UI的,需要调用Handler相关的构造方法,传入主线程的Looper,这样创建的Handler实例,你才能进行UI的更新操作。另外的,需要注意的是,子线程默认是没有开启专属的Looper,所以,在子线程中创建Handler之前,你必须先开启子线程的Looper,否则就会爆出异常,然后GG。从上面贴出的构造方法中的部分就可以知道:
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
以上就是创建Handler的过程,有了Handler实例了,怎样传递消息呢?
2、Handler sendMessage()相关的方法(API 28)
首先上一幅图来表明sendXXXMessageXXX()的相互调用关系:
可以看出,当我们调用Handler进行发送消息时,最终都会调用sendMessageAtTime()方法,最后调用enqueueMessage( ) 发送到消息队列。
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue; //获得当前的消息队列
if (queue == null) { //若是在创建Handler时没有指定Looper,就不会有对应的消息队列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; //这个target就是前面我们说到过的
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
msg.target = this
在发送消息到消息队列之前,明确的指定了消息的target为当前的Handler,以便于在后面Looper分发消息时用到。
queue.enqueueMessage(msg, uptimeMillis)
然后调用了消息队列的enqueueMessage()方法,并传递了两个参数,一个Message,一个是long型的时间。
以上就是Handler的创建和发送消息的过程。
3、Handler dispatchMessage()方法(API 28)
前面说了消息的发送,交给Looper等待处理,处理完后会重新通知Handler处理,那么,是怎样通知Handler处理消息的呢?秘密就在dispatchMessage()这个方法中:
/**
* 在这里处理系统消息
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
/**
* 子类必须实现这个来接收消息
*/
public void handleMessage(Message msg) {
}
当Looper处理完Message后,会使用到Message的target,即上面说到的target,即发送消息的那个Handler,Looper会调用Handler的dispatchMessage()方法分发消息,所以前面在enqueueMessage()发送消息的时候,为什么非得指明Message的target就是这个道理。
回到dispatchMessage()这个方法:
1、首先会判断Message的callback是否为空,此处的callback就是前面我们在Message中说到的,在静态方法创建Message时,可以指定的callback,若不为空,则将结果回调到callback中;
2、若Handler的mCallback 不为空,也一样的道理。
3、平时我们都没有传入这个callback,而是直接实现handleMessage()这个方法,在这个方法中处理更新UI任务。
以上就是Handler发送和接收消息的基本过程:把消息发送到队列—>然后喝茶等待—>接收消息—>分发消息—>在回调中处理。
三、MessageQueue
前面我们知道,Handler发送消息会调用MessageQueue的enqueueMessage()方法,直接上源码(API 28):
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) { //判断msg的所属Handler
throw new IllegalArgumentException("Message must have a target.");
}
//......
synchronized (this) { //因为是队列,有先后之分,所以用了同步机制
//......
msg.when = when;
Message p = mMessages; //对列中排在最后的那个Message
//......
if (p == null || when == 0 || when < p.when) {
//若队列为空,或者等待时间为0,或者比前面那位的等待时间要短,就插队
msg.next = p; //此处的next就是前面我们在Message提到的,指向队列的下一个结点
mMessages = msg;
//......
} else {
//......
Message prev;
for (;;) {
//此处for循环是为了取出一个空的或者when比当前Message长的一个消息,然后进行插入
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
//......
}
msg.next = p; // 置换插入
prev.next = msg; // 置换插入
}
//......
}
return true;
}
以上就是消息队列插入消息的过程原理,通过单向链表的数据结构来存储消息。既然有了插入消息的方法供Handler插入消息,那么应该有对应的取出消息的方法,供Looper调用取出消息处理,它就是Message next()这个方法,代码就不贴了,自行前往查看,过程还是挺简单的。
四、Looper
Looper在Handler机制中扮演着关键的一环,他是循环处理消息的发动机,永不停息(永动鸡),它不断的从消息队列中取出的消息,处理,然后分发处理事件。每个线程都可以且只能绑定一个Looper。主线程之所以能处理消息,也是因为在APP启动时,在ActivityThread中的main()方法中就已经启动了Looper循环。
点击前往查看Looper在main()方法中的启动流程
下面直接上Looper关键方法loop( )的源码(API 28)
public static void loop() {
final Looper me = myLooper(); //获得当前的Looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; //获取当前Looper的消息队列
//......
for (;;) {
Message msg = queue.next(); //取出队头的消息
if (msg == null) {
// 如果消息为空,则跳过,继续执行下一个message
return;
}
//......
try {
msg.target.dispatchMessage(msg);
//......
} finally {
//......
}
//......
msg.recycleUnchecked(); //回收可能正在使用的消息
}
}
由此可见,Looper的处理消息的循环还是挺简单的,就是拿出消息,然后分发,然后回收 … …
总结
Handler机制可以简述为:
Handler将Message发送到Looper的消息队列中,即MessageQueue,等待Looper的循环读取Message,处理Message,然后调用Message的target,即附属的Handler的dispatchMessage()方法,将该消息回调到handleMessage()方法中,然后完成更新UI操作。
Android Handler消息机制实现原理
一、消息机制流程简介
在应用启动的时候,会执行程序的入口函数main(),main()里面会创建一个Looper对象,然后通过这个Looper对象开启一个死循环,这个循环的工作是,不断的从消息队列MessageQueue里面取出消息即Message对象,并处理。然后看下面两个问题:
循环拿到一个消息之后,如何处理?
是通过在Looper的循环里调用Handler的dispatchMessage()方法去处理的,而dispatchMessage()方法里面会调用handleMessage()方法,handleMessage()就是平时使用Handler时重写的方法,所以最终如何处理消息由使用Handler的开发者决定。
MessageQueue里的消息从哪来?
使用Handler的开发者通过调用sendMessage()方法将消息加入到MessageQueue里面。
上面就是Android中消息机制的一个整体流程,也是“Android中Handler,Looper,MessageQueue,Message有什么关系?”的答案。通过上面的流程可以发现Handler在消息机制中的地位,是作为辅助类或者工具类存在的,用来供开发者使用。
对于这个流程有两个疑问:
Looper中是如何能调用到Handler的方法的?
Handler是如何能往MessageQueue中插入消息的?
这两个问题会在后面给出答案,下面先来通过源码,分析一下这个过程的具体细节:
二、消息机制的源码分析
首先main()方法位于ActivityThread.java类里面,这是一个隐藏类,源码位置:frameworks/base/core/java/android/app/ActivityThread.java
publicstaticvoidmain(String[]args){......Looper.prepareMainLooper();ActivityThreadthread=newActivityThread();thread.attach(false);if(sMainThreadHandler==null){sMainThreadHandler=thread.getHandler();}Looper.loop();thrownewRuntimeException("Main thread loop unexpectedly exited");}
Looper的创建可以通过Looper.prepare()来完成,上面的代码中prepareMainLooper()是给主线程创建Looper使用的,本质也是调用的prepare()方法。创建Looper以后就可以调用Looper.loop()开启循环了。main方法很简单,不多说了,下面看看Looper被创建的时候做了什么,下面是Looper的prepare()方法和变量sThreadLocal:
staticfinal ThreadLocal
很简单,new了一个Looper,并把new出来的Looper保存到ThreadLocal里面。ThreadLocal是什么?它是一个用来存储数据的类,类似HashMap、ArrayList等集合类。它的特点是可以在指定的线程中存储数据,然后取数据只能取到当前线程的数据,比如下面的代码:
ThreadLocal
输出的log是
main mThreadLocal=0Thread1 mThreadLocal=1Thread2 mThreadLocal=2main mThreadLocal=0
通过上面的例子可以清晰的看到ThreadLocal存取数据的特点,只能取到当前所在线程存的数据,如果所在线程没存数据,取出来的就是null。其实这个效果可以通过HashMap来实现,考虑线程安全的话使用ConcurrentMap,不过使用Map会有一些麻烦的事要处理,比如当一个线程结束的时候我们如何删除这个线程的对象副本呢?如果使用ThreadLocal就不用有这个担心了,ThreadLocal保证每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。更多ThreadLocal的讲解参考:Android线程管理之ThreadLocal理解及应用场景
好了回到正题,prepare()创建Looper的时候同时把创建的Looper存储到了ThreadLocal中,通过对ThreadLocal的介绍,获取Looper对象就很简单了,sThreadLocal.get()即可,源码提供了一个public的静态方法可以在主线程的任何地方获取这个主线程的Looper(注意一下方法名myLooper(),多个地方会用到):
publicstatic@NullableLoopermyLooper(){returnsThreadLocal.get();}
Looper创建完了,接下来开启循环,loop方法的关键代码如下:
publicstaticvoidloop(){finalLooperme=myLooper();if(me==null){thrownewRuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");}finalMessageQueuequeue=me.mQueue;for(;;){Messagemsg=queue.next();// might blockif(msg==null){// No message indicates that the message queue is quitting.return;}try{msg.target.dispatchMessage(msg);}finally{if(traceTag!=0){Trace.traceEnd(traceTag);}}msg.recycleUnchecked();}}
上面的代码,首先获取主线程的Looper对象,然后取得Looper中的消息队列final MessageQueue queue = me.mQueue;,然后下面是一个死循环,不断的从消息队列里取消息Message msg = queue.next();,可以看到取出的消息是一个Message对象,如果消息队列里没有消息,就会阻塞在这行代码,等到有消息来的时候会被唤醒。取到消息以后,通过msg.target.dispatchMessage(msg);来处理消息,msg.target是一个Handler对象,所以这个时候就调用到我们重写的Hander的handleMessage()方法了。
msg.target是在什么时候被赋值的呢?要找到这个答案很容易,msg.target是被封装在消息里面的,肯定要从发送消息那里开始找,看看Message是如何封装的。那么就从Handler的sendMessage(msg)方法开始,过程如下:
publicfinalbooleansendMessage(Messagemsg){returnsendMessageDelayed(msg,0);}publicfinalbooleansendMessageDelayed(Messagemsg,longdelayMillis){if(delayMillis<0){delayMillis=0;}returnsendMessageAtTime(msg,SystemClock.uptimeMillis()+delayMillis);}publicbooleansendMessageAtTime(Messagemsg,longuptimeMillis){MessageQueuequeue=mQueue;if(queue==null){RuntimeExceptione=newRuntimeException(this+" sendMessageAtTime() called with no mQueue");Log.w("Looper",e.getMessage(),e);returnfalse;}returnenqueueMessage(queue,msg,uptimeMillis);}privatebooleanenqueueMessage(MessageQueuequeue,Messagemsg,longuptimeMillis){msg.target=this;if(mAsynchronous){msg.setAsynchronous(true);}returnqueue.enqueueMessage(msg,uptimeMillis);}
可以看到最后的enqueueMessage()方法中msg.target = this;,这里就把发送消息的handler封装到了消息中。同时可以看到,发送消息其实就是往MessageQueue里面插入了一条消息,然后Looper里面的循环就可以处理消息了。Handler里面的消息队列是怎么来的呢?从上面的代码可以看到enqueueMessage()里面的queue是从sendMessageAtTime传来的,也就是mQueue。然后看mQueue是在哪初始化的,看Handler的构造方法如下:
publicHandler(Callback callback,booleanasync){if(FIND_POTENTIAL_LEAKS){final Classklass=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){thrownewRuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}mQueue=mLooper.mQueue;mCallback=callback;mAsynchronous=async;}
mQueue的初始化很简单,首先取得Handler所在线程的Looper,然后取出Looper中的mQueue。这也是Handler为什么必须在有Looper的线程中才能使用的原因,拿到mQueue就可以很容易的往Looper的消息队列里插入消息了(配合Looper的循环+阻塞就实现了发送接收消息的效果)。
以上就是主线程中消息机制的原理。
那么,在任何线程下使用handler的如下做法的原因、原理、内部流程等就非常清晰了:
newThread(){@Overridepublicvoidrun(){Looper.prepare();Handlerhandler=newHandler();Looper.loop();}}.start();
首先Looper.prepare()创建Looper并初始化Looper持有的消息队列MessageQueue,创建好后将Looper保存到ThreadLocal中方便Handler直接获取。
然后Looper.loop()开启循环,从MessageQueue里面取消息并调用handler的 dispatchMessage(msg) 方法处理消息。如果MessageQueue里没有消息,循环就会阻塞进入休眠状态,等有消息的时候被唤醒处理消息。
再然后我们new Handler()的时候,Handler构造方法中获取Looper并且拿到Looper的MessageQueue对象。然后Handler内部就可以直接往MessageQueue里面插入消息了,插入消息即发送消息,这时候有消息了就会唤醒Looper循环去处理消息。处理消息就是调用dispatchMessage(msg) 方法,最终调用到我们重写的Handler的handleMessage()方法。
三、通过一些问题的研究加强对消息机制的理解
源码分析完了,下面看一下文章开头的两个问题:
Looper中是如何能调用到Handler的方法的?
Handler是如何能往MessageQueue中插入消息的?
这两个问题源码分析中已经给出答案,这里做一下总结,首先搞清楚以下对象在消息机制中的关系:
Looper,MessageQueue,Message,ThreadLocal,Handler
Looper对象有一个成员MessageQueue,MessageQueue是一个消息队列,用来存储消息Message
Message消息中带有一个handler对象,所以Looper取出消息后,可以很方便的调用到Handler的方法(问题1解决)
Message是如何带有handler对象的?是handler在发送消息的时候把自己封装到消息里的。
Handler是如何发送消息的?是通过获取Looper对象从而取得Looper里面的MessageQueue,然后Handler就可以直接往MessageQueue里面插入消息了。(问题2解决)
Handler是如何获取Looper对象的?Looper在创建的时候同时把自己保存到ThreadLocal中,并提供一个public的静态方法可以从ThreadLocal中取出Looper,所以Handler的构造方法里可以直接调用静态方法取得Looper对象。
带着上面的一系列问题看源码就很清晰了,下面是知乎上的一个问答:
Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
原因很简单,循环里有阻塞,所以死循环并不会一直执行,相反的,大部分时间是没有消息的,所以主线程大多数时候都是处于休眠状态,也就不会消耗太多的CPU资源导致卡死。
阻塞的原理是使用Linux的管道机制实现的
主线程没有消息处理时阻塞在管道的读端
binder线程会往主线程消息队列里添加消息,然后往管道写端写一个字节,这样就能唤醒主线程从管道读端返回,也就是说looper循环里queue.next()会调用返回...
这里说到binder线程,具体的实现细节不必深究,考虑下面的问题:
主线程的死循环如何处理其它事务?
首先需要看懂这个问题,主线程进入Looper死循环后,如何处理其他事务,比如activity的各个生命周期的回调函数是如何被执行到的(注意这里是在同一个线程下,代码是按顺序执行的,如果在死循环这阻塞了,那么进入死循环后循环以外的代码是如何执行的)。
首先再看main函数的源码
Looper.prepareMainLooper();ActivityThreadthread=newActivityThread();thread.attach(false);if(sMainThreadHandler==null){sMainThreadHandler=thread.getHandler();}Looper.loop();
在Looper.prepare和Looper.loop之间new了一个ActivityThread并调用了它的attach方法,这个方法就是开启binder线程的,另外new ActivityThread()的时候同时会初始化它的一个H类型的成员,H是一个继承了Handler的类。此时的结果就是:在主线程开启loop死循环之前,已经启动binder线程,并且准备好了一个名为H的Handler,那么接下来在主线程死循环之外做一些事务处理就很简单了,只需要通过binder线程向H发送消息即可,比如发送 H.LAUNCH_ACTIVITY 消息就是通知主线程调用Activity.onCreate() ,当然不是直接调用,H收到消息后会进行一系列复杂的函数调用最终调用到Activity.onCreate()。
至于谁来控制binder线程来向H发消息就不深入研究了,下面是《Android开发艺术探索》里面的一段话:
ActivityThread 通过 ApplicationThread 和 AMS 进行进程间通讯,AMS 以进程间通信的方式完成 ActivityThread 的请求后会回调 ApplicationThread 中的 Binder 方法,然后 ApplicationThread 会向 H 发送消息,H 收到消息后会将 ApplicationThread 中的逻辑切换到 ActivityThread 中去执行,即切换到主线程中去执行,这个过程就是主线程的消息循环模型。
作者:developerzjy
链接:https://www.jianshu.com/p/6cc4d4b4676b
来源:
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。