Android之Activity
Android 之 Activity
启动模式
- standard:每新建一个 Activity 就在栈中新建一个实例
- singleTop:栈顶复用实例
- singleTask: 栈内复用。若不在栈顶,则在把其上面的其他实例推出栈
- singleInstance:在新的任务栈,并且只会有一个实例
复用调用的是onNewIntent(intent)
方法;taskAffinity 属性,为宿主 Activity 指定了存放的任务栈,默认设置为包名,只有和 SingleTask 启动模式匹配时,启动的 Activity 才会运行在名字和 taskAffinity 相同的任务栈中
Intent 中设置启动模式:
- FLAG_ACTIVITY_CLEAR_TOP:singleTask
- FLAG_ACTIVITY_SINGLE_TOP:singleTop
- FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:
android:excludeFromRecents="true"
不会出现在最近任务列表 - FLAG_ACTIVITY_NO_HISTORY:
android:noHistory="true"
这个FLAG启动的Activity,一旦退出,它不会存在于栈中 - FLAG_ACTIVITY_NEW_TASK:需配置 taskAffinity 的值
启动模式常用的使用场景
LauchMode | Instance |
---|---|
standard | 邮件、mainfest 中没有配置就默认标准模式 |
singleTop | 登录界面、WXPayEntryActivity、WXEntryActivty、推送通知栏 |
singleTask | 程序逻辑模块入口:主页面、WebView 页面、扫一扫页面、电商中:购物界面、确认订单界面、付款界面 |
singleInstance | 系统 Launcher、锁屏键、来电显示等系统应用 |
一些可能的问题:若 App 作为 Launcher 启动,被 Android 作为系统任务栈查看不到后台运行应用,此时以普通模式启动另一应用的登录页或其他(如微信),由于处在同一任务栈中,所以查看任务栈时也看不到对应应用。可以通过设置Intent.FLAG_ACTIVITY_NEW_TASK
就可以看到启动的新应用,但于低内存手机或是CPU比较差劲的手机,点击跳转回有明显的停顿,用户体验变差。
生命周期
异常生命周期:非主动退出 Activity(如系统内存足),或是旋转屏幕,导致 Activity 被破坏,需要恢复场景,这时就需要onSaveInstanceState()和onRestoreInstanceState()
.onCreate()
也可恢复状态,需要判空;但是,系统和onRestoreInstanceState()
只有在存在保存状态下才会被调用恢复,因此不需要检查是否 Bundle 为空。
onConfigurationChanged 方法分析:当系统的配置信息发送改变时,系统会调用此方法。只有在配置文件 AndroidManifest 中处理了 configChanges 属性对应的设备配置,该方法才会被调用。如果发送设备配置与在配置文件中设置的不一致,则 Activity 仍会被销毁并使用新的配置重建
configChanges取值:android:configChanges="orientation|screenSize"
横竖屏切换(sdk >= 13)android:configChanges="orientation"
横竖屏切换(sdk < 13)android:configChanges="orientation|keyboard|keyboardHidden"
横竖屏切换(sdk >= 13,兼容一些还是会重建的情况)android: configChanges="keyboard|keyboardHidden|touchscreen"
键盘类型发生改变
屏幕旋转的不确定问题:当你的页面或者 View 被遮挡住( Stop )的时候就不会回调onConfigurationChanged()
,解决方法是定义一个广播接收者来接收 onConfigurationChanged 这个广播。
Activity 启动流程
- 从用户应用进程开始启动,如果是从桌面启动,则为 Launcher 进程,用户进程通过 Binder 机制与 system_server 进程进行通信,发起 startActivity 请求;
- system_server 进程接收到请求后, 向 zygote 进程发送创建进程的请求;
- zygote 进程 fork 出新的子进程,即 APP 进程;
- APP 进程,通过 Binder IPC 向 system_server 进程发起 attachApplication 请求;
- system_server 进程在收到请求后,进行一系列准备工作后,在通过 Binder IPC 向 APP 进程发起 scheduleLaunchActivity 请求;
- APP 进程的 Binder 线程(Application Thread)在收到请求后,通过 handler 向主线程发送 LAUNCH_ACTIVITY 消息;
- 主线程收到 Message 后,创建 Activity,并回调
Activity.onCreate()
等方法。
ActivityManagerService 用于管理所有 Activity 的活动:当接收到启动 Activity 的调用时,使用resolveActivity()
查询系统中符合要求的 Activity;创建使用合适的 ActivityStack 和 Launch Flags 来启动 Activity;若存在可以直接恢复的 Activity,则恢复,否则重新启动;
若不存在应用进程,先创建应用进程。
最终流程又会通过 Binder 调用回到应用进程,使用 ActivityThread 去执行:使用 Instrumentation 去通过反射构建 Activity 实例;使用 Handler 机制调用 Activity 的生命周期。
参考引用
Activity的四种启动模式应用场景
onConfigurationChanged方法介绍及问题解决
屏幕旋转的适配问题以及遇到的一些坑
【凯子哥带你学Framework】Activity启动过程全解析
Activity启动流程(基于Android26)
【深度总结】一个APP从启动到主页面显示经历了哪些过程?