Activity 启动后流程分析
启动流程
App 发起进程:从桌面启动应用,则发起的进程即为 Launcher 所在的进程。从某 App 应用内启动远程的进程,则发送的进程即为该 App 所在的进程。发送进程先通过 binder 发送消息给 system_server 进程。
system_server 进程:调用 Process.Start()
方法,通过 socket 向 Zygote 进程发送创建新进程的请求。
zygote 进程:在执行 ZygoteInit.main()
后便进入 runSelectLoop()
循环体内,当有客户端连接时便会执行 ZygoteConnection.runOnce()
方法,再经过层层调用后 fork 出新的应用进程
新进程:执行 handleChildProc 方法,最后调用 ActivityThread.main()
方法
进程创建的流程图如下:
线程启动
Activity 启动流程
Activity 启动时序图
LaunchMode
standard 是 Activity 默认的启动模式,在不进行显式指定的情况下,所有活动都会自动使用这种启动模式。
每次都会启动一个新的 Activity 放到栈顶 android:launchMode="standard"
,此时每次点击按钮都会创建新的 Activity 实例
代码示例:
点击三次,输出的都是不同的 Activity 实例:
singleTop:当 Activity 的启动模式是 singleTop 时,如果要启动的 Activity 已经处于栈顶,则直接使用,不会再创建新的实例(核心是位于栈顶才会被复用)会回调 onNewIntent 方法 android:launchMode="singleTop"
代码示例:
点击 MainActivity 的 button1,点击多次日志也只会打出一条,也就是说在 singleTop 启动模式下,由于要启动的 MainActivity 实例已经在栈顶,所以不会重新创建,只会存在一个实例,表现上也不会出现 standard 模式下的跳转;点击 MainActivity 的 button2,会跳转到 FirstActivity,这时会创建 FirstActivity 实例并入栈,这时候继续点击 FirstActivity 的按钮 button,会重新创建 MainActivity 实例,因为此时栈顶已经是 FirstActivity 了。
分析:singleTop 适用的场景,通常比较适用于接收到消息后显示的界面。比如 qq 接收消息弹出 Activity 消息界面,需要用一个 activity 实例来展示。还有新闻消息的推送之类的。
singleTask:当活动的启动模式为 singleTask 时,启动该 Activity 会现在栈中检查是否已存在,若存在则直接将该活动之上的 Activity 全部出栈。(跟 singleTop 比较相似,但是这个是用于检测整个栈里是否已经存在要启动的 Activity),也会回调 onNewIntent 方法 android:launchMode="singleTask"
(设置 MainActivity 启动模式为 singleTask)
代码示例:
输出:
查看栈信息:
adb shell dumpsys activity activities
Activities=[ActivityRecord{d6e9fc6 u0 com.randy.launchapp/.MainActivity t4568}]
发现从 SecondActivity 跳转到 MainActivity 之后,Activity 栈中只存在 MainActivity 实例了,FirstActivity 和 SecondActivity 都被从栈里移除了。
分析:singleTask 模式比较适合应用的主界面 activity
singleInstance: 在 singleInstance 模式下,该 Activity 在整个 android 系统内存中有且只有一个实例,而且 该实例单独尊享一个 Task。换句话说,A 应用需要启动的 MainActivity 是 singleInstance 模式,当 A 启动后,系统会为它创建一个新的任务栈,然后 A 单独在这个新的任务栈中,如果此时 B 应用也要激活 MainActivity,由于栈内复用的特性,则不会重新创建,而是两个应用共享一个 Activity 的实例
启动方式的设置
- 通过 AndroidMenifest.xml 文件为 Activity 指定启动模式
- 通过在 Intent 中设置标志位(addFlags 方法) 来为 Activity 指定启动模式
Intent intent = new Intent();
intent.setClass(ActivityB.this,ActivityA.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
- Intent.FLAG_ACTIVITY_NEW_TASK -- singleTask
- Intent.FLAG_ACTIVITY_SINGLE_TOP -- singleTop
- Intent.FLAG_ACTIVITY_CLEAR_TOP -- singleTask
- Intent.FLAG_ACTIVITY_NO_HISTORY -- 使用该模式来启动 Activity,当该 Activity 启动其他 Activity 后,该 Activity 就被销毁了,不会保留在任务栈中。如 A-B,B 中以这种模式启动 C,C 再启动 D,则任务栈只有 ABD
- Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS -- 使用该标识位启动的 Activity 不添加到最近应用列表,也即我们从最近应用里面查看不到我们启动的这个 activity。与属性
android:excludeFromRecents="true"
效果相同
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 并发编程
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论