startActivity原理流程
Android系统中,使用startActivity来启动一个新的activity有两种情况,一种是用户点击桌面APP图标,打开一个APP时候,会调用startActivity来启动APP。另一种就是APP中打开一个新的activity。
上图是startActivity方法调用后,系统源码主要做了哪些事情。
总结来讲:
- 无论是通过桌面APP(LaunchActivity)还是APP内想要打开一个新的activity页面,最终调用的都是activity中的startActivity方法。
- 因为启动一个Activty步骤很繁琐,都是由系统服务AMS统一管理activity的创建和启动,所以这里通过AIDL调用AMS方法来startActivity。
- 其中中间层Instrumentation类主要是为了单元测试而中间代理了一层。
- 回到AMS中,AMS里会先判断当前想要启动的Activty所在的进程是否存在,如果不存在,说明还没启动,这里会决定是否启动其进程,以便后续处理。
- 根据Activity设置的启动模式flag,来确定是否使用缓存的activity还是新建一个activity,以及对该activity栈进行处理,是新建一个,还是直接放到栈中呢?还是需要清理一下栈中其他activity呢?
- 通过上述一系列判断处理,会生成一个对象ActivityRecord对象,该对象主要记录Activty相关信息。
- 根据第4步判断结果,如果目标activity进程不存在,那么会走到zogyte进程中,由zogyte forck出一个进程来启动目标APP,这里接下来会走到目标APP进程的ActivityThread的main方法中,进行后续APP启动流程。如果目标activity进程存在,那么会找到其对应的ApplicationThread代理,通过AIDL方式,调用其对应方法,发送msg消息到ActivityThread中来启动activity。
进入到activityThread进程中后,接下来流程参考APP启动流程。
APP启动流程
对于一个APP进程被fork出来后,会调用执行ActivityThread类中的main方法,该方法会实例化ActivityThread对象,调用其attach方法来开始APP启动流程,同时会开启一个looper死循环。
looper死循环在这里的作用:
- 保证进程可以一直运行。防止程序执行结束了,进程也结束了。
- 用于接收msg消息传给ActivityThread中的handler进行处理。ActivityThread为APP主线程。
- 为什么looper不会造成主线程ANR呢?
- 因为一个程序的运行,如果逻辑执行结束了,那么程序也就结束了,这里使用looper死循环,保证了APP进程一直存活着,而不会结束。
- 第二点就和ANR的本质以及looper原理有关了,下篇文章会分析下。
下图主要是APP启动流程图。
总结下:
- 调用AMS中的方法开始流程
- 通过传入的ApplicationThread代理,调用其方法进行Application对象的创建,在APP进程中会发送创建Application的消息到looper队列中。
- 保存当前进程到ProcessRecord中
- AMS通过ApplicationThread代理发送消息给looper,告知其创建Activity
- 如果存在需要启动的Service,AMS通过aApplicationThread代理发送消息给looper,告知其创建Service。
- 如果存在静态广播,AMS会进行广播的处理和分发。
在APP进程中
- 收到创建APPlication的消息-> 通过LoadAPK来统一创建Application对象,且调用其onCreate方法
- 收到创建activity的消息 -> 通过LoadAPK来创建Activity,且根据需要调用其生命周期方法
- 收到创建service的消息 -> 创建service实例,且调用其onCreate方法
- 为什么ActivityThread中要使用队列来处理消息呢?
- 首先APP进程每个组件有其生命周期概念,周期是线性的,即方法调用是线性的,不能存在同时调用两个生命周期方法,比如同时调用onCreate和onStart方法,因为每个生命周期方法有其特殊含义。所以这里使用队列来做限制,可以保证线性处理。
- 生命周期方法的调用处理需要一定时间,但是AMS调用APP进程方法后,并不能等待其完全执行完后才可以继续处理,所以AMS进程只需要通过AIDL方式发送消息后,然后就可以继续做接下来的事情了,不需要等待APP进程方法的执行。