GVKun编程网logo

【Android】Android四大组件之Activity(android的4大组件)

25

想了解【Android】Android四大组件之Activity的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于android的4大组件的相关问题,此外,我们还将为您介绍关于Android四

想了解【Android】Android四大组件之Activity的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于android的4大组件的相关问题,此外,我们还将为您介绍关于Android 四大组件 (一) Activity 生命周期、Android 四大组件之 Activity、Android 四大组件之 Activity 解析(上)、Android 四大组件之 Activity 解析(下)的新知识。

本文目录一览:

【Android】Android四大组件之Activity(android的4大组件)

【Android】Android四大组件之Activity(android的4大组件)

Activity是与用户交互的接口。
Android系统是通过Activity栈的形式来管理Activity。
Activity的4种状态:Active / Paused / Stopped / Killed。

Activity是什么

Activity是Android的四大组件之一。是用户操作的可视化界面;它为用户提供了一个完成操作指令的窗口。当我们创建完毕Activity之后,需要调用setContentView()方法来完成界面的显示;以此来为用户提供交互的入口。在Android App 中只要能看见的几乎都要依托于Activity,所以Activity是在开发中使用最频繁的一种组件。

Activity的生命周期

在Android中会维持一个Activity Stack(Activity栈),当一个新的Activity创建时,它就会放到栈顶,这个Activity就处于运行状态。当再有一个新的Activity被创建后,会重新压人栈顶,而之前的Activity则会在这个新的Activity底下,就像子弹被压入枪梭一样。而且之前的Activity就会进入后台。

一个Activity实质上有四种状态

  • 运行中(Running/Active):这时Activity位于栈顶,是可见的,并且可以用户交互。
  • 暂停(Paused):当Activity失去焦点,不能跟用户交互了,但依然可见,就处于暂停状态。当一个新的非全屏的Activity或者一个透明的Activity放置在栈顶,Activity就处于暂停状态;这个时候Activity的各种数据还被保持着;只有在系统内存在极低的状态下,系统才会自动的去销毁Activity。
  • 停止(Stoped):当一个Activity被另一个Activity完全覆盖,或者点击HOME键退入了后台,这时候Activity处于停止状态。这里有些是跟暂停状态相似的:这个时候Activity的各种数据还被保持着;当系统的别的地方需要用到内存时,系统会自动的去销毁Activity。
  • 销毁(Detroyed):当我们点击返回键或者系统在内存不够用的情况下就会把Activity从栈里移除销毁,被系统回收,这时候,Activity处于销毁状态。

上面的四种状态稍微笼统的介绍了一下Activity在不同时期的状态,接下来通过具体的回调方法看一下Activity的生命周期,下面是官网提供的一张Activity在各个状态下回调用的回调方法:

在这里插入图片描述

这张图包含了Activity从被创建到被销毁的几乎所有生命周期的回调函数。从上面的方法名我们就可以猜到其大概的功能。一会我们会细讲。我们上面说到了Activities的四种状态,但是这些方法是在什么状态下调用的呢?

在Activity运行之前,会通过onCreate(),onStart(),onResume();当运行完onResume()之后,Activity就处于上面说的Running/Active 状态了。

当Activity处于暂停状态时,会调用onPause(),这个时候Activity还是见的。当在这个时候Activity恢复到运行状态时,会重新调用onResume()。

当Activity处理停止状态时,会调用onStop(),这个时候如果要恢复到运行状态就会调用一个新的方法onRestart(),然后去调用onStart(),onResume()。

当Activity被销毁时,就会调用onDestroy(),那么如果要恢复Activity的显示就需要重新创建这个Activity;重新去走onCreate(),onStart(),onResume()这三个方法。

虽然通过字面意思可以大概了解这些方法的作用,但是我们还是需要说一下,它们的具体功能。

onCreate: 当Activity第一次被创建时调用。是生命周期开始的第一个方法。在这里我们可以做一些初始化的操作,比如:调用setContentView()方法去加载界面,绑定布局里的一些控件,初始化一些Activity需要用到的数据。之后会调用onStart方法.

onStart:当Activity正在变为可见时调用。这个时候Activity已经可见了,但是还没有出现在前台还不能跟用户交互。可以简单理解为Actvity已经可见但是还没有出现在前台。之后会调用onResume.

onResume:当Activity可以跟用户交互时调用,这个时候,这个Activity位于栈的顶部。跟onStart相比,它们都是表示Activity已经可见,但是onStart调用时Activity还在后台,而调用onResume时,Activity已经进入了前台,可以跟用户交互了。之后会调用 onPause.

onPause:当Activity暂停时调用这个方法;在这里我们可以用来保存数据,关闭动画和其它比较耗费cpu的操作;但是在这里做的操作绝对不能耗时,因为如果当前Activity要启动一个新的Activity,这个新的Activity会在当前Activity执行完毕onPause之后才能进入可见状态。这个方法之后一般会调用的方法有onStop或者onResume.

onStop:当Activity进入后台,并且不会被用户看到时调用。当别的Activity出现在前台时,或者Activity会被销毁时,调用此方法;在这个方法调用之后,系统可能会在内存不够的情况下回收Activity;在这个方法之后一般会调用onRestart或者onDestroy.

onDestroy:这个方法是Activity生命周期中调用的最后一个方法。它会在Activity被销毁之前调用;Activity销毁原因一般是我们调用Activity的finish方法手动销毁,另一个就是系统在内存紧张的情况下去销毁Activity,以用来节省空间。我们可以通过方法 isFinishing 来判断Activity是否正在被销毁。

onRestart:这个方法是在Activity处于停止状态后,又回到可视状态时调用。之后会调用onResume.

以上是Activity的生命周期方法,除此之外Activity还有两个方法感觉大家也应该知道,虽然它们不属于Activity的生命周期方法。这俩方法是:onSaveInstanceState 和 onRestoreInstanceState。,

onSaveInstanceState
它不属于Activity的生命周期方法,不一定会被触发,但是当应用遇到意外情况,比如:内存紧张,用户点击了Home键或者用户按下电源键关闭屏幕等这些情况,这时系统可能会去销毁Activity,这时这个方法就会被调用。这里强调的是系统去回收Activity,而不是我们去手动的销毁Activity。这个方法提供了一个Bundle对象,我们可以通过它来保存一些临时性的状态或者数据。通常这个方法只适合保存临时数据,如果需要数据的持久化保存等操作,还是要在onPause方法里执行才好。当 Activity再次被创建时,Activity会通过onCreate(Bundle)或者onRestoreInstanceState(Bundle)执行的时候,会将提供一个的Bundle对象来恢复这些数据。

onRestoreInstanceState
这个方法调用的前提是,Activity必须是被系统销毁了,在Activity被再次创建时它会在onStart()方法之后被调用。

下面总结一下Activity的生命周期:

正常情况下Activity的生命周期是:
onCreate->onStart->onResume->onPause->onStop->onDestroy

  1. 对于一个正常的Activity,第一次启动,会依次回调以下方法:
    onCreate->onStart->onResume

  2. 当我们打开一个新的Activity或者点击Home键回到桌面后,会依次回调以下方法:
    onPause->onStop

上面提到过,如果新的Activity是透明的(采用的透明主题),当前的Activity不会回调onStop.

  1. 当我们再次回到原Activity,会依次回调以下方法:
    onRestart->onStart->onResume

  2. 当我们点击返回键后,会依次回调以下方法:
    onPause->onStop->onDestroy.

  3. 当Activity被系统回收后,再次被打开,会跟第一次启动的时回调生命周期方法一样(不包含 onSaveInstanceState 和 onRestoreInstanceState)。

  4. 我们可以注意到 其中onCreate 跟 onDestroy 是相对的。一个创建一个销毁。并且其只可能被调用一次。按照这种配对方式,我们也可以看出 onStart跟onStop 是配对的,这两个方法可以被多吃调用。onResume 和 onPause 也是配对的,它们一个获取焦点和用户交互,一个正好相反。

  5. onStart和onResume,onPause和onStop,这两对方法在功描述差不多,那为什么还要重复存在呢?
    其实这两对方法分别代表不同的意义,onStart和onStop 是Activity是否可见的标志,而onResume和onPause是从Activity是否位于前台的标志,它们针对的角度不同。

  6. 在onPause里不能做耗时操作,因为如果要启动一个新的Activity,新的Activity必须要在前一个Activity的onPause 方法执行完毕之后才会启动的新的Activity。

上面是正常情况下的生命周期方法调用,下面简单说一下异常情况下Activity的生命周期:

在系统内存不够时会根据优先级杀死Activity。怎么判断Activity的优先级呢?

  1. 最高的优先级:在前台显示并且跟用户交互的Activity,优先级最高,
  2. 暂停状态的Activity优先级次之:如果Activity没有在前台,但是可见,不可与用户交互,比如弹出一个对话框等。
  3. 处于后台Activity优先级最低:执行了onStop方法的Activity优先级最低。它不可见,并且无法跟用户交互。

当系统内存不足,就会按照优先级去销毁Activity,在销毁Activity时会额外的在onPause和onStop之间调用onSaveInstanceState;当要重新创建这个Activity 时,会在onStart方法之后调用onRestoreInstanceState方法。

Android 四大组件 (一) Activity 生命周期

Android 四大组件 (一) Activity 生命周期

 

简单粗暴。

分两块来熟悉activity生命周期:一.典型生命周期过程;二.异常情况下的生命周期过程。

 

一. 典型生命周期过程

Activitiy的生命周期方法主要有七个:onCreate()、onRestart()、onStart()、onResume()、onPause()、onStop()、onDestory()。

 1. onCreate()

      onCreate方法是整个生命周期中唯一必须实现的方法。布局都是在Activity中进行,在该方法中做一些初始化的操作,如通过setContentView设置界面布局的资源,初始化所需要的组件信息等。

 2. onRestart()

    当Activitiy被onStop()并且没有被killed时候,调用这个方法进行唤醒,也可以说理解为,当处于非栈顶状态的活动需要再次返回栈顶,展现给用户的时候,触发该方法。该方法优先于onStart()方法。

 3.onStart()

    表示Activity正在启动,但是无法与用户进行交互。可以把onStart和onStop看成一对。

 4.onResume()

    Activity已在前台可见,可与用户交互了。

   onResume方法与onStart的相同点是两者都表示Activity可见,只不过onStart回调时Activity还是后台无法与用户交互,而onResume则已显示在前台,可与用户交互。

 5.onPause()

   这个方法之后有可能是onResume也有可能是onStop。用于提交未保存发生变化了的持久化数据,及停止动画及其他其他比较消耗CPU的事件,这是为了更好的运行新的activity。当在activity中打开的是一个dialog不完全覆盖这个activity,则activity就会是onPause状态。

 6.onStop()

   activity完全看不见的时候,会调用onStop方法。当用户自己退出程序的时候,建议在onStop方法中保存数据。此时Activity不可见,仅在后台运行。同样地,在onStop方法可以做一些资源释放的操作(不能太耗时)。

 7.onDestroy()

    Activity正在被销毁,也是生命周期最后一个执行的方法,一般我们可以在此方法中做一些回收工作和最终的资源释放。

 

二、异常情况下的生命周期过程

异常生命周期产生原因一般有这两种:

1.横竖屏切换;

    Activity处于竖屏状态,如果突然旋转屏幕,由于系统配置发生了变化,在默认的情况下,Activity会被销毁并重新创建。

  

   可以在onSaveInstanceState方法中存储一些数据以便Activity重建之后可以恢复这些数据。onSaveInstanceState和onRestoreInstanceState只有在Activity异常终止时才会被调用的,正常情况是不会调用这两个方法的。

  当我们不想Activity在屏幕旋转后导致销毁重建时,可以设置configChange=“orientation”;当SDK版本大于13时,我们还需额外添加一个“screenSize”的值,对于这两个值含义如下:
orientation:屏幕方向发生变化,配置该参数可以解决横竖屏切换时,Activity重建问题(API<13)
screenSize:当设备旋转时,屏幕尺寸发生变化,API>13后必须配置该参数才可以保证横竖切换不会导致Activity重建。
设置了这两个参数后,当横竖屏切换时,Activity不会再重建并且也不会调用之前相关的方法,取而代之的是回调onConfigurationChanged方法.

2.内存不足的时候killed优先级低的activity.

  android系统中进程优先级由高到低依次是:前台进程,可见进程、服务进程、后台进程、空进程.

Android 四大组件之 Activity

Android 四大组件之 Activity

Activity,Android 四大組件之一,主要用于显示与用户交互的界面。

在开发中新建一个实现 Activity 的类时,会默认继承 AppCompatActivity,该类的继承关系如下:

AppCompatActivity <- FragmentActivity <- ComponentActivity <- Activity <- ContextThemeWrapper <- ContextWrapper <- Context

说明 Activity 类在之后被改动了多次。

Activity 的生命周期:

打开(onCreate,onStart,onResume),关闭或 kill(onPause,onStop,onDestroy)

切换到另外 Activity,桌面或其他 App(onPause,onStop),回到 Activity(onRestart,onStart,onResume)

旋转(onPause,onStop,onDestroy,onCreate,onStart,onResume,先关闭再打开)

弹出关闭 Dialog 周期不变,被系统 kill 周期函数也不会被调用

数据保存:在 Activity 中避免数据突然丢失时,可将临时数据保存在 onSaveInstanceState 方法中,在 onCreate 中取出,并通过 Bundle 来 put 数据。永久数据保存在 onPause 方法中。

Activity 有四种启动方式:

  • standard

默认模式,以叠加的方式将 Activity 加入到栈中

  • singleTop

对应要启动的 Activity 如果是在栈顶,那么不会新建,否则会重新创建一个 Activity

  • singleTask

如果栈中存在对应的 Activity,则使用该 Activity,否则创建新的 Activity

  • singleInstanst

启动 Activity 时会新建一个任务栈来存放,如果已经有相同的 Activity 存在,则会重用。

taskAffinity 可以指定 Activity 放在哪个栈 Task 中,默认是包名

Activity 在启动时也可以设置一些样式,如动画等

Activity 任务栈:每启动一个 App 就会新建一个任务栈,桌面 launch 本身也是一个任务栈,任务栈通过 id 和 taskAffinity 来标识 

在开发中,通常会使用 Stack 来统一管理 Activity。

使用 startActivity (Intent) 可以实现 Activity 之间的跳转。

 

 

 

 

 

 

 

 

Android 四大组件之 Activity 解析(上)

Android 四大组件之 Activity 解析(上)

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 = "黑体">运行效果如下所示:


隐式启动Activity
<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的生命周期如下图所示:
多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 = "黑体">打印日志如下所示:
singleInstance
<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的方法

Android 四大组件之 Activity 解析(下)

Android 四大组件之 Activity 解析(下)

segmentfault 对 mackdown 语法的支持不是很好,有些图片都显示不出来,大家可以去我的掘金查看这篇文章。

一、Activity 回顾

<font face= 黑体>在 完全看懂 Android 四大组件之 Activity(上)中我们已经讲了 Activity 的启动方法生命周期以及启动模式。这一节我们来讲一下 Activity 之间的传参以及如何启动系统 Activity 这两大知识点。其中 Activity 之间的传参又包括利用 Intent 传参利用Bundle传参以及复杂数据的传递

二、Activity 之间的数据传递

2.1、利用 Intent 传递数据

<font face= 黑体>利用 Intent 传递数据主要是调用 Intent.putExtra() 方法,这个方法有两个参数,第一个参数是 name,第二个参数是 value,value 的类型如下所示:

Intent方法
<font face= 黑体>传递数据的具体代码如下所示:

// 1、利用 Intent 传递数据
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("str", "Android 开发");  // 传递 String
intent.putExtra("flag", true);
startActivity(intent);

<font face= 黑体>传递的代码已经写完了,那么怎么接收呢?我们可以在 SecondActivity 利用 getIntent() 方法接收数据,具体如下所示:

TextView params = findViewById(R.id.tv_params);
// 接收数据
String str = getIntent().getStringExtra("str");
// 这里的 false 是默认值的意思,如果没有接收到 flag 的值就是 false
boolean flag = getIntent().getBooleanExtra("flag", false);
if (flag) {
    params.setText(str);
} else {
    params.setText("没有接受到数据");
}

<font face= 黑体>我们来看下效果:

传递数据

2.2、利用 Bundle 传递数据

<font face= 黑体>利用 Bundle 传递数据主要是是利用 Bundle 先将要传递的数据存储起来,然后再将 Bundle 数据集传递给需要接收的 Activity,我们来看下传递的代码:

// 2、利用 Bundle 传递数据
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
Bundle bundle = new Bundle();
bundle.putString("str", "Android 开发");
bundle.putBoolean("flag", true);
intent.putExtra("myBundle", bundle);    
startActivity(intent);

<font face= 黑体>接收 Bundle 也很简单,我们只需要调用 getIntent().getBundleExtra() 方法就可以了,我们来看下代码:

Bundle bundle = getIntent().getBundleExtra("myBundle");
if (bundle != null) {
    String str = bundle.getString("str");
    boolean flag = bundle.getBoolean("flag");
    if (flag) {
        params.setText(str);
    } else {
        params.setText("没有接受到数据");
    }
}

<font face= 黑体>Bundle 传递数据跟 Intent 传递数据效果上是完全一样的,只是写法上有点不同而已。

2.3、Activity 间复杂数据的传递

<font face= 黑体>上面这两个方法,可以传递任何基本类型的数据,但是如果想传递一个复杂的数据(比如一个对象),那么要怎么办呢?Android 给我们提供了两种方法来传递复杂类型的数据:

2.3.1、把需要传递的类实现 Serilziable 接口

<font face= 黑体>这里我们创建一个 UserInfo 类来实现 Serilziable 接口,具体代码如下所示:

import java.io.Serializable;

public class UserInfo implements Serializable {
    public String username;
    public int age;
    public int gender;
}

<font face= 黑体>传递的代码如下所示:

// 3、复杂类型的数据传递  实现 Serializable 接口
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
UserInfo userInfo = new UserInfo();
userInfo.username = "Bob";
userInfo.age = 25;
userInfo.gender = 1;
intent.putExtra("userInfo", userInfo);
startActivity(intent);

<font face= 黑体>接收 Serializable 对象,我们需要调用 getIntent().getSerializableExtra() 方法,我们来看下代码:

UserInfo userInfo = (UserInfo) getIntent().getSerializableExtra("userInfo");
if (userInfo != null) {
    String str = "名字:" + userInfo.username + " " + "年龄:" + userInfo.age + " " + "性别:" +
            (userInfo.gender == 1 ? "男" : "女");
    params.setText(str);
}

<font face= 黑体>我们来看下效果:

对象数据

2.3.2、把需要传递的类实现 Parceable 接口

<font face= 黑体>这里我们创建一个 Order 类来实现 Parceable 接口,我们只需要去重写 describeContents 方法和 writeToParcel 方法就可以了,Creator 是自动生成的,具体代码如下所示:

public class Order implements Parcelable {

    public String address;
    public boolean isReceived;
    public int count;

    public Order() {
    }

    protected Order(Parcel in) {
        address = in.readString();
        isReceived = in.readByte() != 0;
        count = in.readInt();
    }

    public static final Creator<Order> CREATOR = new Creator<Order>() {
        @Override
        public Order createFromParcel(Parcel in) {
            return new Order(in);
        }

        @Override
        public Order[] newArray(int size) {
            return new Order[size];
        }
    };

    @Override
    public int describeContents() {
        // 只有当对象中存在文件描述符的时候才需要返回 1,通常情况下返回 0 即可
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(address);
        dest.writeBoolean(isReceived);
        dest.writeInt(count);
    }
}

<font face= 黑体>传递的代码如下所示:

// 4、复杂类型的数据传递  实现 Parcelable 接口
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
Order order = new Order();
order.address = "测试地址";
order.isReceived = true;
order.count = 5;
intent.putExtra("order", order);
startActivity(intent);

<font face= 黑体>接收 Parcelable 对象,我们需要调用 getIntent().getParcelableExtra() 方法,我们来看下代码:

Order order = getIntent().getParcelableExtra("order");
if (order != null) {
    String str = "地址:" + order.address + " " + "购买数量:" + order.count + " " + "是否已经确认收货:" +
            (order.isReceived ? "是" : "否");
    params.setText(str);
}

<font face= 黑体>我们来看下效果:

复杂数据

2.4、Activity 数据回传

<font face= 黑体>当第二个 Activity 需要回传数据到第一个 Activity 的时候,我们只需要通过 startActivityForResult() 方法来启动第二个 Activity 即可,当第二个 Activity 关闭的时候,Android 系统会回调第一个 Activity 的 onActivityResult() 方法,在这个方法里面我们可以获取第二个 Activity 回传过来的一些数据。

<font face= 黑体>MainActivity 具体代码如下所示:

public class MainActivity extends AppCompatActivity {

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

        findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 5、Activity 数据回传
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivityForResult(intent, 1000);
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        String backData = data.getStringExtra("back_data");
        Log.e("MainActivityTag", "requestCode:" + requestCode + " " + "resultCode:" + resultCode + " " +
                "回传的数据:" + backData);
    }
}

<font face= 黑体>SecondActivity 具体代码如下所示:

public class SecondActivity extends AppCompatActivity {

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

        Intent intent = new Intent();
        intent.putExtra("back_data", "回传数据是。。。。。。。。");
        setResult(RESULT_OK, intent);
    }
}

<font face= 黑体>结果如下所示:

在这里插入图片描述

三、启动系统的 Activity

<font face= 黑体>Android 系统常用的 Activity 组件包括拨打电话发送短信以及打开相机,启动方法分别是:

  • <font face= 黑体>intent.setAction(Intent.ACTION_DIAL);
  • <font face= 黑体>intent.setAction(Intent.ACTION_SENDTO)
  • <font face= 黑体>intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE)

<font face= 黑体>具体代码如下所示:

  1. 拨打电话

    Intent intent = new Intent();
    intent.setAction(Intent.ACTION_DIAL);
    startActivity(intent);
  2. 发送短信

    Intent intent = new Intent();
    intent.setAction(Intent.ACTION_SENDTO);
    Uri smsToUri = Uri.parse("smsto:" + 10086);
    intent.setData(smsToUri);
    intent.putExtra("sms_body", "短信内容");
    startActivity(intent);
  3. 打开相机

    Intent intent = new Intent();
    intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
    startActivity(intent);

<font face= 黑体>具体效果如下所示:
演示

四、小结

<font face= 黑体>到这里为止,我们已经讲了 Activity 的五种启动方法生命周期四种启动模式Activity 之间数据的传递如何启动系统 Activity 组件

今天关于【Android】Android四大组件之Activityandroid的4大组件的讲解已经结束,谢谢您的阅读,如果想了解更多关于Android 四大组件 (一) Activity 生命周期、Android 四大组件之 Activity、Android 四大组件之 Activity 解析(上)、Android 四大组件之 Activity 解析(下)的相关知识,请在本站搜索。

本文标签: