Android之Activity

Android 之 Activity

启动模式

  1. standard:每新建一个 Activity 就在栈中新建一个实例
  2. singleTop:栈顶复用实例
  3. singleTask: 栈内复用。若不在栈顶,则在把其上面的其他实例推出栈
  4. singleInstance:在新的任务栈,并且只会有一个实例

复用调用的是onNewIntent(intent)方法;taskAffinity 属性,为宿主 Activity 指定了存放的任务栈,默认设置为包名,只有和 SingleTask 启动模式匹配时,启动的 Activity 才会运行在名字和 taskAffinity 相同的任务栈中

Intent 中设置启动模式:

  1. FLAG_ACTIVITY_CLEAR_TOP:singleTask
  2. FLAG_ACTIVITY_SINGLE_TOP:singleTop
  3. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:android:excludeFromRecents="true"不会出现在最近任务列表
  4. FLAG_ACTIVITY_NO_HISTORY:android:noHistory="true"这个FLAG启动的Activity,一旦退出,它不会存在于栈中
  5. 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 启动流程

Activity 启动流程

  1. 从用户应用进程开始启动,如果是从桌面启动,则为 Launcher 进程,用户进程通过 Binder 机制与 system_server 进程进行通信,发起 startActivity 请求;
  2. system_server 进程接收到请求后, 向 zygote 进程发送创建进程的请求;
  3. zygote 进程 fork 出新的子进程,即 APP 进程;
  4. APP 进程,通过 Binder IPC 向 system_server 进程发起 attachApplication 请求;
  5. system_server 进程在收到请求后,进行一系列准备工作后,在通过 Binder IPC 向 APP 进程发起 scheduleLaunchActivity 请求;
  6. APP 进程的 Binder 线程(Application Thread)在收到请求后,通过 handler 向主线程发送 LAUNCH_ACTIVITY 消息;
  7. 主线程收到 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从启动到主页面显示经历了哪些过程?