关于Android消息机制的源码分析
1.应用程序入口分析
应用程序入口是在ActivityThread
类里main
方法,(当应用启动后,底层通过C/C++调用main方法)。
核心代码:
1.1 初始化了Environment对象,然后创建了Lopper,然后开始消息循环。如果程序没有死循环,执行完main函数就会立马退出。之所以App可以一直运行是因为Looper.loop()
是一个死循环。
这里用for(;;)
而不是while(true)
是为了防止一些人通过黑科技修改这个标志位(通过反射机制)(这里不是很懂)!
在非主线程里面我们也可以创建一个Handler,但是需要我们主动去为当前的子线程绑定一个Looper,并且启动消息循环
Looper有两个核心方法:prepare()与loop()。通过Looper、Handle、Message、MessageQueue等组成了Android的消息处理机制。
2.为什么需要这样一个消息机制
2.1 不阻塞主线程
Android应用启动时,会创主线程, 负责与UI组件(widget,view)进行交互, 比如控制UI界面显示,更新等。这种单线程模型导致运行性大大降低,只能处理简单、短暂的操作。过重的任务比如下载访问数据库等都会导致ANR。Android大部分耗时操作都应该放到子线程,不要在主线程做操作
2.2 并发程序的有序性
单线程模型的UI主线程也是不安全的,会造成不可确定的结果。
线程不安全简单理解为:多线程访问资源时,有可能出现多个线程先后更改数据造成数据不一致。比如,A工作线程(也称为子线程)访问某个公共UI资源,B工作线程在某个时候也访问了该公共资源,当B线程正访问时,公共资源的属性已经被A改变了,这样B得到的结果不是所需要的的,造成了数据不一致的混乱情况。
线程安全简单理解为:当一个线程访问功能资源时,对该资源进程了保护,比如加了锁机制,当前线程在没有访问结束释放锁之前,其他线程只能等待直到释放锁才能访问,这样的线程就是安全的。
Android只允许主线程更新UI界面,子线程处理后的结果无法和主线程交互,即无法直接访问主线程,这就要用到Handler机制来解决此问题。基于Handler机制,在子线程先获得Handler对象,该对象将数据发送到主线程消息队列,主线程通过Loop循环获取消息交给Handler处理。
有了消息机制,我们可以发送消息,然后Looper把消息发给主线程,然后就可以执行了。
消息包括:
我们自己的操作消息,即客户端的Handler
操作系统的操作消息,系统的Handler,例如来电话跳出界面,就需要。
先分析系统的Handler,再去深入理解消息机制里面各个组件
3.系统的Handler
ActivityThread的成员变量有这样一个H(继承自Handler),这个就是系统的Handler。
回顾一下ActivityThread的初始化,在main方法中ActivityThread thread = new ActivityThread();
在new的时候就已经完成了初始化成员变量,单例饿加载。
在H中定义了大量的常量,然后用case做操作。
从系统的Handler中,在handlerMessage我们可以看到四大组件的生命周期操作,创建,销毁,切换等。跨进程通信及Application进程的销毁。
比如说我们有一个 应用程序A 通过 Binder 去跨进程启动另外一个 应用程序B 的 Service(或者同一个应用程序中不同进程的Service),如图:AMS是四大组件的生命周期的一个比较重要的类,IPC机制会涉及
最后AMS接收到消息后,发送消息到MessageQueue里面,最后由系统的Handler处理启动Service的操作:
在handlerCreateService()里通过反射的方式去newInstance(),并且毁掉了Service的Oncreate方法。
又例如我们可以通过发SUICIDE消息可以自杀,这样来退出应用程序。
应用程序退出
实际上我们要退出应用程序的话,就是让主线程结束,换句话说就是要让 Looper 的循环结束。这里是直接结束 Looper 循环,因此我们四大组件的生命周期方法可能就不会执行了,因为四大组件的生命周期方法就是通过 Handler 去处理的,Looper 循环都没有了,四大组件还玩毛线!因此我们平常写程序的时候就要注意了,onDestroy 方法是不一定能够回调的。
这里实际上是调用了 MessageQueue 的 quit,清空所有 Message。
4.消息机制的分析
4.1 消息对象Message的分析
提到消息机制,在MessageQueue里面存在的就是我们Message对象。
Message 里面有一些我们常见的参数,arg1 arg2 obj callback when 等等。这里要提一下的就是这个 target 对象,这个对象就是发送这个消息的 Handler对象,最终这条消息也是通过这个 Handler 去处理掉的。
4.2 消息的循环过程分析
1.拿到Looper()对象(me),如果当前线程没有Looper,那么就抛出异常。这就是为什么在子线程里面创建Handler如果不手动创建启动Looper会报错的原因。
2.拿到Looper的成员变量MessageQueue,在MessageQueue里面不断地去区消息,关于MessageQueue的next用法如下:
这里可以看到消息的取出用到了一些native方法,这样做是为了获得更高的效率,消息的去取出并不是直接就从队列的头部取出的,而是根据了消息的when时间参数有关的,因为我们可以发送延时消息、也可以发送一个指定时间点的消息。因此这个函数有点复杂,我们点到为止即可。
3、继续分析 loop方法:如果已经没有消息了,那么就可以退出循环,那么整个应用程序就退出了。什么情况下会发生呢?还记得我们分析应用退出吗?
在 系统Handler 收到 EXIT_APPLICATION 消息的时候,就会调用 Looper 的 quit方法:
原文:大专栏 Android消息机制