Activity生命周期、启动模式总结

291 阅读6分钟

一、生命周期

image

1. 生命周期流程

onCreate

进行一些初始化工作

onStart

由不可见变为可见,但未在前台,无法交互
Activity已经显示出来,但我们还看不到

onResume

可见,前台,可交互

onPause

正在停止;

onPause必须先执行完,新的Activity才会启动。

  • 如A启动B:A.onPause --> B.onCreate、B.onStart、B.onResume --> A.stop
  • 所以避免在onPause中做耗时操作,容易造成卡顿
  • 打开新的Activty为透明主题或dialog:只调用onPause,不会回调onStop

onStop

即将停止;
做一些重量级的回收工作,不能太耗时。

  • 释放可能泄露内存的资源,因为onDestory不一定会调用。

onDestory

即将销毁

  • finish或系统kill进程时,onDestory不确定会立即调用,也不确定一定会调用
  • 非必须的情况下,减少在这里释放资源

2.其它情况生命周期

2.1 透明覆盖、半遮挡

如图分支1,当A启动的Activity为透明主题,或弹出Dialog时:

  • A只是onResume和onPause之间切换

2.2 启动Activity

如图分支2

  • A启动B:A.onPause --> B.onCreate、B.onStart、B.onResume --> A.stop
  • B返回键到A: B.pause --> A.onRestart、A.onStart、A.resume --> B.stop、destory

2.3 异常关闭

如图分支3,常见场景为:
启动其它Activity、Home键返回、锁屏...

onCreate(Bundle savedInstanceState)

bundle != null时为异常关闭后,系统重新创建

onRestart、onStart

onRestoreInstanceState

该回调一定是被回收后重建时调用

onResume、onPause

onSaveInstanceState

  • 系统觉得有可能被回收时调用(并不一定得被回收了才调用)
  • 在onStop之前,和onPause没有既定时序关系
onStop、onDestory
2.3.1 onRestore和onSave不一定是成对出现的
  • onSaveInstanceState系统觉得有可能会被回收就调用,此时onRestoreInstanceState不一定会被调用
  • onCreate中bundle != null、onRestoreInstanceState被调用了,说明异常终止了,onSaveInstanceState就会被调用
2.3.2 资源相关配置改变

当横竖屏切换时,系统会先将当前Activity销毁,然后重建一个新的。为了避免这样销毁重建的过程,可以在AndroidMainfest.xml中对OrientationActivity对应的配置

configChanges="orientation|keyboardHidden|screenSize"
2.3.3 系统内存不足被杀死,优先级:

前台进程>可见进程>service进程>后台进程>空进程

二、启动模式

standard
  • 默认启动模式,
  • 最通常,谁启动就在谁所在的任务栈。
  • ApplicationContext启动standard模式,报错
    • standard模式进入启动它的Activity所在的栈
    • ApplicationContext没有任务栈
    • 指定FLAG_ACTIVITY_NEW_TASK标记位,创建新的任务栈,实际是以singTask模式启动
singleTop
  • 栈顶复用模式,栈顶有就复用,不会重建。
    通过onNewIntent方法接收参数,onCreate、onReusme等方法不会被调用,因为它没有发生改变。
singleTask
  • 栈内复用模式,单例模式,栈内有该Activity实例,则多次启动不会重新创建。
    通过onNewIntent传递参数,onCreate等不会被调用。
  • singleTask自带clearTop效果,会将该Activity实例以上的Activity出栈。如,ADCB,启动D,则栈内情况为AD,CB会被出栈。
  • 启动singleTask模式时的过程:
    当启动A时,系统先查找有没有A想要的任务栈(和TaskAffinity有关):
    如果没有,就创建新的任务栈,压入A;
    如果有,再查看栈内有没有A的实例:没有就创建压入A;有A的实例就复用,如果不在栈顶,就清空A实例以上的Activity。
  • 与TaskAffinity配合
singleInstance
  • 加强的singleTask模式
  • 全局单例模式,整个系统中是单例的
  • 具有独占性,即它会独自占用一个任务
  • 被他开启的任何activity都会运行在其他任务中?
allowTaskReparenting

允许activity重新指定Task

android:allowTaskReparenting=["true" | "false"]
android:alwaysRetainTaskState=["true" | "false"]
android:clearTaskOnLaunch=["true" | "false"]
android:finishOnTaskLaunch=["true" | "false"]
android:noHistory=["true" | "false"]
android:taskAffinity="string"
TaskAffinity

任务相关性,标识了Activity所需要的任务栈的名字。

  • 只有和singleTask配合使用才会有效

  • 没有TaskAffinity:

    • 自己或别的APP启动都在默认的包名栈中
    • 被其它APP启动后,home,点击图标,直接进入该页面(此时存在:App2栈、App1栈)
  • 有TaskAffinity:

    • 自己或别的APP启动都在设置的包名栈中
    • 被其它APP启动后,home,点击图标,进入APP2的主页面(此时存在:App2栈、设置的包名栈、App1栈)
  • 任务栈:只能以出栈入栈的方式,不能排序。先入后出。

总结

  • 非Activity类型的context,standard模式启动Activity时报错。
    需加上FLAG_ACTIVITY_NEW_TASK,这时是以singTask模式启动。
  • 如果复用,通过onNewIntent传递参数
    可在该方法中setIntent,以便在其它方法中getIntent拿到Intent
  • standard、singTop:谁启动,在谁的栈里
模式 应用场景
standard 正常启动Activity
singleTop 启动同类型的页面,例如通知内容显示页面、搜索页面
singleTask 作为程序入口
singleInstance 需要与程序分离开的页面,例如闹铃的响铃界面、支付界面

三、dumpsys

通过dumpsys命令查询系统服务的运行状态(对象的成员变量属性值)。查看activity,广播,服务,电池,CPU等信息。

adb shell dumpsys activity     
adb shell dumpsys activity a 包名  查看指定包名下的Activity栈信息
查找 "Running activites"

dumpsys命令用法
AMS之dumpsys篇

四、FLAG标志

内容杂乱,不做研究,用到再查阅。

五、匹配规则

Intent和过滤器
Intent 与 IntentFilter 匹配规则——张拭心

  • Intent启动:Activity、Service、BroadcastReceiver

filter过滤规则

  • 可以有多个intent-filter,同时匹配到action、category、data才算完全匹配,匹配任意一组即成功。
  • 每个filter可以有多个action、category、data。
action匹配规则
  • Intent中没有action匹配失败
  • Intent中的任意一个action能匹配任意一个filter中的action即可

即:Intent中的action存在且必须匹配filter中的其中一个action。(只要有一个匹配上,Intent中其它的action没有匹配上也行)

category匹配规则
  • Intent中可以没有category(系统默认加上DEFAULT这个category)
  • 如果有,都必须和filter中的category匹配上
  • 注意和action的区别
    • action:至少有一个能匹配filter中的
    • category:可以没有,如果有,所有的category都必须和filter中的匹配上

即:可以没有,如果有需和filter中全部匹配上。

data匹配规则

intent 中的 data 至少可以匹配过滤器中的一个。

通过隐式启动一个组件之前,可以先判断一下是否有符合条件的组件。
PackageManager/Intent:resolveActivity()

<activity
    android:name=".activity.launchmode.SingleTaskActivity"
    android:alwaysRetainTaskState="true"
    android:label="singleTask"
    android:launchMode="singleTask"
    android:taskAffinity="top.varmin.task2">
    <intent-filter>
        <action android:name="top.varmin.action.test"/>
        <category android:name="top.varmin.category.test"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
    
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>

        <data
            android:host="myapp.mycompany.com"
            android:scheme="myapp"/>
    </intent-filter>
</activity>