Activity 生命周期和启动模式

Activity 生命周期

onCreate()

表示 activity 正在被创建,是所有声明周期的第一个方法。在这个方法中,做一些初始化操作,加载布局文件,初始化数据等。

onStart()

表示 Activity 正在被启动,即将开始。这时 Activity 已经可见了,但是还没有出现在前台,还无法和用户交互。可以理解为还没给钱,能看不能摸(误)。

一般在 onCreate() 之后调用,或者在 onRestart() 之后调用。

onResume()

表示给钱了,现在 Activity 出现在了前台并开始活动,也可以接受用户事件。

onPause()

表示 Activity 正在停止,可以做一些简单的存储数据、停止动画之类的操作,但是不能耗时太长,因为这个方法结束之后,下一个 activity 才能执行 onCreate()

onStop()

表示 Activity 即将停止,可以做一些稍微重量级的回收工作,也不能太耗时

onDestroy()

表示 Activity 即将被销毁,最后一个生命周期回调,释放资源,回收内存,防止泄露

onRestart()

表示 Activity 正在重新启动,一般指从不可见状态回到可见状态时会回调到这里。

比如回到桌面再看打开,或者跳转到下一个 Activity 再回来。

Tips

  1. 一般来讲,onStart() 和 onStop()、onResume() 和 onPause() 是两对回调方法,作用没什么差别,只不过是两个角度划分, onStart() 和 onStop() 是从 Activity 是否可见,onResume() 和 onPause() 是从 Activity 是否在前台;
  2. 起点 Activity 的 onPause() 执行完毕后才能执行终点 Activity 的 onCreate(),所以切记不能在onPause() 中做耗时操作;

异常情况下的生命周期回调

系统配置改变导致的 Activity 重建

最经典的就是横竖屏切换的场景。用户切换横竖屏的时候,Activity 会销毁后重建,同时会调用 onSaveInstanceState() 方法来存储数据,然后在重建的时候会通过 onCreate() 的参数将之前的保存的 bundle 信息返回回来,同时回调 onRestoreInstanceState() 方法恢复数据。

  1. 如果是销毁后重建,那 onCreate 方法的 Bundle 参数不为空,会包含销毁前保存的数据;

  2. onSaveInstanceState() 方法在 onStop() 之前调用,但相对于 onPause() 的调用时机并不固定;

  3. onRestoreInstanceState() 方法在 onStart() 之后调用,相对于 onResume() 的调用时机不固定;

  4. 所有的 View 的状态也都能得到保存和恢复,是通过 Activity 委托 Window,Window 委托 DecorView,最后 DecorView 遍历子元素,一一委托实现的。

    所有的 View 都实现了 onSaveInstanceState() & onRestoreInstanceState() 方法来处理意外情况。

  5. 在清单文件中设置 android:configChanges 属性为 orientation 就可以禁止屏幕旋转时重建。

资源内存不足导致优先级低的 Activity 被杀死

优先级排序:可交互 > 可见 > 不可见。

如果有任务脱离四大组件运行在后台,那很快就会被系统杀死并回收资源。

比较好的处理方式是依托于 Service,运行于后台,保持一个比较高的优先级。

Activity 启动模式

启动模式老生常谈了,今天说点儿不一样的。

先说设置启动模式有两种方式:

1、在清单文件中配置,standard,singleTask,singleTop,singleInstance;

2、直接在启动的时候通过给 Intent 设置标记位实现,优先级更高,可以覆盖掉清单文件的配置;

3、两种方式其实不能简单比较,因为在限定条件上有所不同,比如功能清单不能设置 clear_top 标志,而代码无法设置 singleInstance 启动模式。

再说一下任务栈。

Activity 中有任务栈的概念,分为前台任务栈和后台任务栈,后台任务栈中的 Activity 都处于暂停状态,用户可以通过切换将后台任务栈再次调到前台。

默认情况下,一个程序的任务栈都是以包名为名的,但是开发者可以通过给 taskAffinity 属性赋值来为某个 Activity 指定任务栈。指定任务栈一般要和 singleTask 或者 allowTaskReparenting 配合使用,否则没什么意义。

这个后边再展开说,先来看四个启动模式。

standard

在标准启动模式下,被启动的 Activity 应该运行在发起启动的 Activity 所在的任务栈中。

举例来说,如果使用 getApplicationContext() 启动 Activity,系统就会直接报错。因为 Application Context 非 Activity 类型,没有任务栈。

解决办法是给待启动的 Intent 添加一个 NEW_TASK 的标记,这时候就会为目标 Activity 新建一个任务栈启动,但是这时候本质上就不是以标准模式启动的了,而是 singleTask;我们在前面说了,代码设置标记优先级更高。

singleTop

栈顶复用,如果目标 Activity 位于栈顶就不再重新创建实例,而是回调 onNewIntent() 方法,从该方法的参数中能拿到这次请求的信息。

如果栈顶不是目标 Activity,那就新建一个实例,从头完整走生命周期方法。

举个栗子。现在任务栈里,ABCD 4 个 activity,A 底 D 顶。

1、如果再启动一次 D,D 是 singleTop,那就还是 ABCD;

2、如果再启动一次 C,C 是 singleTop,那就是 ABCDC;

singleTask

栈内复用,和 singleTop 差不多,位于栈顶的话回调 onNewIntent 方法;如果不位于栈顶,有几种情况:

1、默认任务栈,但是不在栈顶,比如说 ADBC,要以 singleTask 模式启动 D,singleTask 默认带有 clearTop 的效果,任务栈里就会变成 AD

2、重新指定了任务栈,任务栈不存在,实例也不存在,那就先创建任务栈,然后创建 activity,最后入栈;

singleInstance

加强版的 singleTask,singleTask 还可以位于默认任务栈里,这个是纯单例,强制开启一个新的任务栈。自己一个人在一个任务栈里,还 clearTop,有一种独孤求败的感觉。

说一个 taskAffinity 和 singleTask 配合的实例。

A 正常启动模式,B、C singleTask,同时单独设置 taskAffinity;

然后 A 启动 B,B 启动 C,C 启动 A,A 再启动 B,这时候连续按下两次返回键,出现的是哪个 Activity?

答案是桌面。

首先,A 自己位于一个任务栈内,B、C 位于一个任务栈,且 singleTask,C 再去启动标准模式的 A 时,A 会进入调用者的任务栈中,也就是 B、C 所在的栈;

然后,A 再启动一次 B,这时候栈结构是 BCA,B 又是 singleTask,直接会将 CA 出栈,将 B 显示会栈顶;

再然后,这时候有两个任务栈,一个是默认的,里边有一个 A;另一个是单独开辟的,里边有一个 B。

这时候连续按两次返回,就退出应用了,也就回到了桌面。

IntentFilter 匹配规则

IntentFilter 主要用于隐式调用。IntentFilter 主要有三种,action、data、category。


        
                
                
                
        
        
        
        

action、data、category 可以有多个,只要有一个 Intent 能同时匹配,就可以成功跳转。

intent-filter 也可以分组声明,Intent 匹配上任意一组 IntentFilter 也可以实现跳转。

action

如果过滤规则中定义了 action,那 Intent 中就必须有 action,且能够与某一个 action 完全相同才可以匹配成功。

category

category 不是必须的,如果在源码中会自动加上 android.intent.category.DEFAULT

data

和 action 一样,如果定义了就必须在 Intent 中携带,否则匹配失败。

具体的 data 类型不再赘述,使用场景不多,简单了解即可。

有一类 action 和 category 比较重要,它们就是:



这二者共同作用的用来标明这是一个入口 activity,并且会出现在系统的应用列表中,二者缺一不可。

另外,针对 service 和 broadcast receiver,PackageManager 同样提供了类似的方法获取成功匹配的组件信息。

你可能感兴趣的:(Activity 生命周期和启动模式)