关于android:Android-Activity启动方法生命周期启动模式详细解析

0次阅读

共计 8141 个字符,预计需要花费 21 分钟才能阅读完成。

segmentfault 对 mackdown 语法的反对不是很好,有些图片都显示不进去,大家能够去我的掘金查看这篇文章。

一、概述

<font face = “ 黑体 ”> 简略来讲,Activity 就是一个可视化界面,负责承建一个屏幕窗口,避免 UI 组件,供用户交互。一般来说承建 Activity 有三个步骤:

  1. <font face = “ 黑体 ”> 承建 Activity 类;
  2. <font face = “ 黑体 ”> 在 AndroidManifest.xml 中注册;
  3. <font face = “ 黑体 ”> 设置布局文件(可选)。

二、Activity 的启动办法

2.1、显示启动

<font face = “ 黑体 ”> 明确指定要启动的 Activity 的 $\color{red}{class}$ 或者 $\color{red}{包名.activity 类名}$,显示启动次要有三种形式:

  • 形式一:<font color = red>class 跳转(最罕用)

    Intent intent = new Intent(MainActivity.this, SecondActivity.class);
    startActivity(intent);
  • 形式二:<font color = red> 包名. 类名 跳转

    Intent intent = new Intent();
    intent.setClassName(MainActivity.this, "com.zjgsu.activitydemo.SecondActivity");
    startActivity(intent);
  • 形式三:<font color = red>ComponentName 跳转

    Intent intent = new Intent();
    intent.setComponent(new ComponentName(MainActivity.this, SecondActivity.class));
    startActivity(intent);

2.2、隐式启动

<font face = “ 黑体 ”> 设置启动过滤器,通过指定的 $\color{red}{action}$ 或 $\color{red}{action 和 data}$ 属性,零碎会查找符合条件的 Activity,并启动它,隐衷启动次要有两种形式:

  • 形式一:<font color = red> 传入 actionName

    Intent intent = new Intent("abcd.SecondActivity");
    startActivity(intent);
  • 形式二:<font color = red> 设置 action

    Intent intent = new Intent();
    intent.setAction("abcd.SecondActivity");
    startActivity(intent);

<font face = “ 黑体 ” color = red> 留神:如果本人定义的某个 Activity 要通过隐式启动,在 AndroidManifest.xml 中必须加上 android.intent.category.DEFAULT,否则不起作用。

 <activity android:name=".SecondActivity">
     <intent-filter>
         <action android:name="abcd.SecondActivity"/>
         <category android:name="android.intent.category.DEFAULT"/>
     </intent-filter>
 </activity>

2.2.1、隐式启动如果两个 activity 的 actionName 是一样的会怎么呢?

<font face = “ 黑体 ”> 如下所示,我创立了两个 Activity,而后这两个 Activity 的 actionName 我设置成一样的,而后我通过隐式启动 Activity,会怎么呢?

<activity android:name=".SecondActivity"
   android:label="第二个界面">
    <intent-filter>
        <action android:name="abcd.SecondActivity" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

<activity android:name=".ThirdActivity"
    android:label="第三个界面">
    <intent-filter>
        <action android:name="abcd.SecondActivity" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

<font face = “ 黑体 ”> 运行成果如下所示:


<font face = “ 黑体 ”> 看下面的 gif 动图咱们就可以看进去,这种状况下 Android 会让咱们抉择要运行的 Activity。即当有多个 Action 匹配隐式匹配的条件时,将会弹出抉择框供用户抉择。

三、Activity 的生命周期

<font face = “ 黑体 ”> 咱们就以上面这张 Activity 生命周期图为例子吧:

<img src = “https://img-blog.csdnimg.cn/20200922214426970.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zODQ3ODc4MA==,size_16,color_FFFFFF,t_70#pic_center” width=”500″ height=”420″></img>

<font face = “ 黑体 ”> 一个 Activity 启动的时候会顺次调用 onCreate() –> onStart() –> onResume() –> onPause() –> onStop() –> onDestroy()。当执行到 onResume() 的时候这个 Activity 就变成了可操作状态。

3.1、单 Activity 生命周期的调用程序

  • onCreate()    创立 Activity 时调用
  • onStart()    当 Activity 界面变为用户可见时调用
  • onResume()    当 Activity 界面获取到焦点时调用(<font size = 2> 界面按钮可点击,文本框可输出等)
  • onPause()    当 Activity 界面失去焦点时调用(<font size = 2> 界面按钮不可点击,文本框不可输出等)
  • onStop()    当 Activity 界面变为用户不可见时调用
  • onDestroy()    当 Activity 被销毁时调用
  • onRestart()    当 Activity 再次启动时调用

3.2、多 Activity 生命周期的调用程序

<font face = “ 黑体 ”> 多 Activity 的生命周期如下图所示:

<font face = “ 黑体 ”> 下面那张图的操作流程:关上 A activity,点击按钮启动 B activity,在 B activity 中点击返回键。代码运行截图如下:

四、Activity 的启动模式

<font face = “ 黑体 ”>Activity 的启动模式决定了新生产的 Activity 实例是否重用已存在的 Activity 实例,是否和其余 Activity 实例共用一个 Task。Task 是一个具备栈构造的对象,一个 Task 能够治理多个 Activity,启动一个利用,也就创立一个与之对应的 Task。

4.1、四种启动模式

  1. standard
    <font face = “ 黑体 ”> 默认的启动模式,每次激活 Activity 时(startActivity),都创立 Activity 实例,并放入工作栈;
  2. singleTop
    <font face = “ 黑体 ”> 每次激活 Activity 时,判断该 Activity 实例是不是在栈顶,如果是,不须要创立,否则须要创立 Activity 实例;
  3. singleTask
    <font face = “ 黑体 ”> 如果要激活的那个 Activity 在工作栈中曾经存在了,则不须要创立,只须要把此 Activity 以上的 Activity 实例都出栈,这个时候此 Activity 就到栈顶了,若不存在,就创立 Activity 实例;
  4. singleInstance
    <font face = “ 黑体 ”> 只有一个实例,并且这个实例独立运行在一个 Task 中,这个 Task 只有这个实例,不容许有别的 Activity 实例存在。

4.2、四种启动模式代码演示

4.2.1、standard

<font face = “ 黑体 ”> 咱们先来看下成果:


能够看到,在 SecondActivity 外面再次启动 SecondActivity,standard 模式下的启动形式会再次创立 SecondActivity 实例。使得工作栈中蕴含了两个 SecondActivity 实例,所以咱们点击返回键只是返回了上一个 SecondActivity,再次按返回键才回到 MainActivity。

<font face = “ 黑体 ”> 次要代码如下所示:

// 启动模式是 standard,不填默认就是 standard
<activity android:name=".SecondActivity"
    android:launchMode="standard"/>

// SecondActivity
public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        findViewById(R.id.btn_start_self).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {startActivity(new Intent(SecondActivity.this, SecondActivity.class));
            }
        });
    }
}

4.2.2、singleTop

<font face = “ 黑体 ”> 咱们还是用下面的例子来演示,只是把 SecondActivity 的启动模式改成 singleTop,咱们来看下成果:


能够看到,这个时候在 SecondActivity 外面再次启动本人,是不会创立 SecondActivity 实例的,应该这个时候 SecondActivity 曾经在栈顶了,而 singleTop 启动模式会判断该 Activity 实例是不是在栈顶,如果是,不须要创立,否则才创立 Activity 实例。

<font face = “ 黑体 ”> 次要代码如下所示:

<activity android:name=".SecondActivity"
    android:launchMode="singleTop"/>

<font face = “ 黑体 ” color = red>问题 1 :如果这时候咱们再创立一个 ThirdActivity,在 MainActivity 启动 SecondActivity,再在 SecondActivity 外面启动 ThirdActivity,而后在 ThirdActivity 外面启动 SecondActivity,这时候工作栈中 Activity 的实例程序是怎么的?

<font face = “ 黑体 ” color = red>:工作栈中自底向上的 Activity 实例程序为 MainActivity–>SecondActivity–>ThirdActivity–>SecondActivity。

4.2.3、singleTask

<font face = “ 黑体 ”> 咱们用下面的问题的例子来演示,只是把 SecondActivity 的启动模式改成 singleTask,咱们来看下成果:


这个时候工作栈中自底向上的 Activity 实例程序为 MainActivity–>SecondActivity。因为 SingleTask 启动模式如果栈中存在 Activity 实例会把该 Activity 以上的所有 Activity 实例全副出栈。

<font face = “ 黑体 ”> 次要代码如下所示:

<activity android:name=".SecondActivity"
    android:launchMode="singleTask"/>

4.2.4、singleInstance

<font face = “ 黑体 ”>singleInstance 启动模式和 singleTask 启动模式有点像,都会保障工作栈中只有同一个 Activity 的实例,然而 singleInstance 会创立一个新的 Task。要想演示 singleInstance,咱们须要把每个 Activity 所在的栈的 ID 打印进去。例子同上,只是批改启动模式为 singleInstance。

<font face = “ 黑体 ”> 打印日志如下所示:

<font face = “ 黑体 ”> 咱们看到 SecondActivity 所在工作栈的 TaskId 是 592,而 MainActivity 和 ThirdActivity 所在工作栈的 TaskId 是 591。这就阐明 SecondActivity 运行在一个独立的工作栈外面,这个工作栈外面只有 SecondActivity 这一个 Activity 实例。打印 TaskId 的办法如下:

Log.e("activityDemo2TAG", "ThirdActivity 所在的 task 的 id 为:" + getTaskId());

五、利用 IntentFlag 设置 Activity 的启动形式

<font face = “ 黑体 ”> 解说这个知识点之前咱们先来看一下 Task 和 taskAffinity 这两个概念、

5.1、Task 基本概念

  • <font face = “ 黑体 ”>Task 是一个具备栈构造的容器,能够搁置多个 Activity 实例;
  • <font face = “ 黑体 ”> 启动一个利用,零碎会为之创立一个 Task,来搁置根 Activity;
  • <font face = “ 黑体 ”> 一个 Activity 启动另一个 Activity 时,默认状况下两个 Activity 是搁置在同一个 Task 中的,后者被压入前者所在的 Task 栈,当用户按下返回键,后者从 Task 中被弹出,前者又显示在栈顶。

5.2、taskAffinity 基本概念

  • <font face = “ 黑体 ”> 定义了 Activity 实例想要进入的 Task;
  • <font face = “ 黑体 ”> 如果一个 Activity 没有显示的指明该 Activity 的 taskAffinity 属性,那么它的这个属性就等于 Application 所指明的 taskAffinity,如果 Application 也没有指明,那么该 taskAffinity 的值就等于包名。

5.3、IntentFlag 的罕用值

<font face = “ 黑体 ”>IntentFlag 的品种很多,咱们这里就只筛选几个平时罕用的来解说一下。

5.3.1、FLAG_ACTIVITY_NEW_TASK

<font face = “ 黑体 ”> 零碎会寻找或创立一个新的 Task 来搁置指标 Activity,寻找时根据指标 Activity 的 taskAffinity 属性进行匹配,如果找到一个 Task 的 taskAffinity 与之雷同,就将指标压入此 Task 中,如果查找无果,则创立一个新的 Task,并将该 Task 的 taskAffinity 值设置为指标 Activity 的 taskAffinity,将指标 Activity 搁置于此 Task 中。

5.3.1.1、代码演示

<font face = “ 黑体 ”> 设置 IntentFlag 的办法:

Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

<font face = “ 黑体 ”>$\color{red}{第一种状况}$:以 FLAG_ACTIVITY_NEW_TASK 形式启动 SecondActivity,然而 SecondActivity 不增加 taskAffinity 属性,咱们来看下成果:

<font face = “ 黑体 ”> 能够看到,咱们尽管以 FLAG_ACTIVITY_NEW_TASK 启动,然而两个 Activity 所在的 Task 还是同一个,这是为什么呢?那是因为 如果一个 Activity 没有显示的指明该 Activity 的 taskAffinity 属性,那么它的这个属性就等于 Application 所指明的 taskAffinity,如果 Application 也没有指明,那么该 taskAffinity 的值就等于包名。 也就是说此时 SecondActivity 和 MainActivity 两个 taskAffinity 的值都是包名,所以 SecondActivity 必定会被放入 MainActivity 所在的栈中了。

<font face = “ 黑体 ”>$\color{red}{第二种状况}$:以 FLAG_ACTIVITY_NEW_TASK 形式启动 SecondActivity,并且 SecondActivity 设置 taskAffinity 属性:

<activity android:name=".SecondActivity" 
    android:taskAffinity="flag.newIntent.test"/>

<font face = “ 黑体 ”> 咱们来看下成果:

<font face = “ 黑体 ”> 能够看到这时候 SecondActivity 和 MainActivity 曾经不在同一个栈外面了。

5.3.2、FLAG_ACTIVITY_SINGLE_TOP

<font face = “ 黑体 ”> 同四种启动模式中的 singleTop,这里就不演示了。

5.3.3、FLAG_ACTIVITY_CLEAR_TOP

<font face = “ 黑体 ”> 同四种启动模式中的 singleTask,这里也不演示。

5.3.4、FLAG_ACTIVITY_REORDER_TO_FRONT

<font face = “ 黑体 ”> 这个启动模式的意思是如果栈中曾经存在 Activity 实例,会将它拿到栈顶,不会启动新 Activity,也不会删除它之上的 Activity 实例。

5.3.4.1、代码演示

<font face = “ 黑体 ”> 咱们先来看下成果:


<font face = “ 黑体 ”> 咱们在 MainActivity 外面启动 SecondActivity,而后在 SecondActivity 外面启动 ThirdActivity,而后再在 ThirdActivity 外面通过 FLAG_ACTIVITY_REORDER_TO_FRONT 的形式启动 SecondActivity,这个时候因为栈中曾经有 SecondActivity 实例了,所以会把该实例拿到栈顶,并且不会销毁 SecondActivity 之上的所有实例,所以此时栈自底向上的 Activity 实例程序是 MainActivity –> ThirdActivity –> SecondActivity。

六、小结

<font face = “ 黑体 ”> 这篇文章次要讲了 Activity 的五种启动办法,包含三种显示启动和两种隐式启动,又讲了单和多 Activity 的生命周期,以及在 AndroidManifest 中通过 lunchMode 设置 Activity 的启动模式和通过 Intent.setFlag() 办法设置 Activity 的启动模式。

<font face = “ 黑体 ”> 下一篇文章咱们将会解说在 Activity 中 利用 Intent 传参 利用 Bundle 传递数据 简单数据的传递 以及 启动零碎 Activity 的办法

正文完
 0