抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

Activity

介绍

Activity(活动)是一个核心的组件,负责应用界面的呈现和用户交互。每个 Activity 通常表示应用中的一个屏幕,比如一个登陆页面、设置页面、或图片查看页面。Activity 管理用户操作的生命周期和状态变更,同时也负责在屏幕上显示 UI 并响应用户输入。

Activity 是 Android 应用中的基本单元,每一个 Activity 代表应用的一个“页面”或“任务”。一个 Android 应用可以由多个 Activity 组成,它们通过 Intent 进行交互和导航。在 Android 中,Activity 是通过继承 android.app.Activity 类来创建的,Andorid 应用中每个 Activity 都必须在 AndroidManifest.xml 配置文件中进行注册,否则系统将不识别也不执行该 Activity。

活动流程

创建活动

创建一个 activity

配置

app/src/main/java/com.example.Nactivity 目录是空的,创建一个 activity,New-> Activity-> Empty viw Activity

前两个选项不选。勾选上第一个表示自动为 FirstActivity 创建一个对应的布局文件,勾选第二个表示会自动将 FirstActivity 设置为当前项目的主活动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.example.nactivity;

import android.os.Bundle;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class FirstActivity extends AppCompatActivity {

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

创建和加载布局

Android 程序设计讲究的是逻辑和视图分离,每个活动最好都能对应一个布局,而布局就是用来显示界面内容的,因此我们现在手动创建一个布局文件

右击 app/src/main/res 目录 →New→Directory, 会弹出一个新建目录的窗口, 这里先创建一个名为 layout 的目录。然后对着 layout 目录右键 →Layout resource file, 又会弹出一个新建布局资源文件的窗口, 我们将这个布局文件命名为 first_layout, 根元素就默认选择为 LinearLayout。

Design 是当前的可视化布局编辑器,在这里可以预览当前的布局,也可以通过拖放的方式编辑布局。而 Code 里面存放的是 XML 方式来编辑布局。这里我们添加一个 button 1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button 1"
tools:ignore="MissingConstraints" />

</androidx.constraintlayout.widget.ConstraintLayout>

android: id 定义了一个唯一标识符,@+id/id_name 是用来定义一个 id。

android: layout_width 指定当前 button 的宽度,match_parent 是让它和父元素一样宽。

android: layout_height 指定当前 button 的高度,wrap_content 表示 button 高度只要能刚好包含里面的内容就行。

android: text 指定 button 中显示的文字内容。

在 onCreate 中增加 setContentView;,用来给当前活动加载一个布局,而它的参数是一个布局文件的 id。

1
setContentView(R.layout.first_layout);

AndroidManifest.xml 中注册

所有的活动都要在 AndroidManifest.xml 中进行注册才能生效,而实际上 NActivity 已经在 AndroidManifest.xml 中注册过了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Nactivity"
tools:targetApi="31">
<activity
android:name=".FirstActivity"
android:exported="false" />
</application>

</manifest>

可以看到活动的注册声明要放在 application 里面,这里通过标签来对活动进行注册的,这个注册环节是 Android Studio 自动帮我们完成的。

android: name 指定具体注册哪一个活动.FirstActivity 是 com.example.activitytest.FirstActivity 的缩写。

可是目前程序还是不能跑起来的,因为我们还没有指定主活动,也就是说程序运行起来时,不知道首先启动哪个活动。

添加如下代码,然后启动

1
2
3
4
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>

android: label 显示在左上角,中间就是 layout 布局文件的效果

在活动中使用 Toast

Toast 是 Android 系统中提供的一种非常好的提醒方式,在程序中可以使用它将一些短小的信息通知给用户,这些信息会在一段时间后自动消失,并且不占用任何屏幕空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.example.nactivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class FirstActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
Button button1=(Button)findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {

public void onClick(View view) {
Toast.makeText(FirstActivity.this, "Click The Button!", Toast.LENGTH_SHORT).show();
}
});
}
}

我们首先通过 findViewById 获得按钮的实例,findViewById 返回值是一个 View 对象,需要我们向下转型为 Button 对象。在得到实例后,通过调用 setOnClickListener 为按钮注册一个监听器,点击按钮时会执行监听器中的 onClick 方法,因此 Toast 的弹出需要在 onClick 方法中编写。第一个参数是 Context, 也就是 Toast 要求的上下文, 由于活动本身就是一个 Context 对象, 因此这里直接传入 FirstActivity.this 即可。第二个参数是 Toast 显示的文本内容, 第三个参数是 Toast 显示的时长, 有两个内置常量可以选择 Toast, LENGTH SHORT 和 Toast.LENGTH LONG。

在活动中使用 Menu

由于手机的屏幕空间十分有限,因此要充分利用屏幕空间在手机界面设计中就显得非常重要了,可能有时候大量的菜单就占了屏幕 1/3 的空间,不过安卓给我们提供了一种方式,不仅可以让菜单都得到展示的同时,还不用占用任何屏幕空间。

首先在 res 目录下新建一个 menu 文件夹。接着在这个文件夹下再新建一个名叫 main 的菜单文件, 右击 menu 文件夹 →New→Menu resource file, 接下来我们需要在 main.xml 中添加以下代码

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/add_item"
android:title="Add"
/>
<item
android:id="@+id/remove_item"
android:title="Remove" />
</menu>

这里我们创建了两个菜单项,其中标签就是用来创建具体的某一个菜单项,然后通过 android: id 给这个菜单项指定一个唯一的标识符,通过 android: title 给这个菜单项指定一个名称。

接下来回到 FirstActivity 中来重写 onCreateOptionsMenu()方法,快捷键 Ctrl+O

1
2
3
4
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main,menu);
return true;
}

通过 getMenuInflater 方法能够得到 MenuInflater 对象,再调用它的 inflate 方法就可以给当前活动创建菜单了。

inflate 有两个参数,第一个参数用于指定我们通过哪一个资源文件来创建菜单,这个传入 R.menu.main,第二个参数用于指定我们的菜单项将添加到哪一个 Menu 对象中,这里直接用 onCreateOptionsMenu 传入的 menu,然后返回 true,表示允许创建的菜单显示出来,如果返回了 false,创建的菜单将无法显示。

当然,仅仅让菜单显示出来肯定还不够,我们需要让菜单真正能用才行,因此还要再定义菜单响应事件,在 FirstActivity 中重写 onOptionsItemSelected 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.example.nactivity;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class FirstActivity extends AppCompatActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int itemId = item.getItemId(); //Resource IDs will be non-final by default in Android Gradle Plugin version 8.0
if (itemId == R.id.add_item) {
Toast.makeText(this, "You click Add", Toast.LENGTH_SHORT).show();
} else if (itemId == R.id.remove_item) {
Toast.makeText(this, "You click Remove", Toast.LENGTH_SHORT).show();
}
return true;
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
Button button1=(Button)findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {

public void onClick(View view) {
Toast.makeText(FirstActivity.this, "You Click The Button!", Toast.LENGTH_SHORT).show();
}
});

}
}

销毁一个活动

如果你不想通过按建的方式, 而是希望在程序中通过代码来销毁活动, 当然也可以, Activity 类提供了一个 finish()方法, 我们在活动中调用一下这个方法就可以销毁当前活动了。

1
2
3
4
5
6
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});

生命周期

每个 Activity 都有自己的生命周期,管理其状态的生命周期回调方法被系统自动调用。Activity 类中定义了 7 个回调方法,覆盖了活动生命周期的每一个环节。

回调方法(Callback Method)是 Android 框架调用的特定方法,开发者通过实现或重写这些方法来定制组件的行为和响应特定事件。Android 系统会根据组件的状态、生命周期或用户的操作自动调用这些回调方法,这样开发者不需要在每个时刻显式监控和控制应用状态变化,而只需在特定的方法中实现相应的逻辑。

  • onCreate// 响应点击事件

当 Activity 首次创建时调用,仅在 Activity 生命周期中调用一次。在这个方法中完成活动的初始化操作,比如说加载布局、绑定事件等。

  • onStart// 进行资源准备,例如更新界面内容

onCreate() 之后或从“停止”状态恢复时调用。此时 Activity 即将对用户可见。在 onStart() 中,Activity 从后台进入前台,但还没有进入可交互状态。此时适合准备即将显示的资源,例如更新界面元素的内容。

  • onResume// 开始接收用户输入、动画等

onStart() 之后调用,表示 Activity 进入“运行”状态,此时用户可以与之交互。在此方法中,Activity 完全进入前台并获得焦点,可以接收用户输入。适合在此开启动画、视频或音频播放等需要用户直接交互的内容。

  • onPause// 暂停耗资源的操作,例如动画、音频

当 Activity 即将进入“停止”状态或系统要启动其他 Activity 时调用。在 onPause() 中,可以释放与用户交互相关的资源,暂停动画或视频,并确保数据的保存。Activity 在“暂停”状态仍然可见,但失去焦点,不再与用户交互。由于随时可能调用 onStop(),建议在此方法中保存当前状态,以便系统回收时数据不丢失。

  • onStop // 释放大资源,避免内存占用

当 Activity 对用户完全不可见时调用。适合释放不再需要的资源(如取消网络请求、释放数据库或大图资源等),防止内存泄漏。可以在 onStop() 中保存状态,以备下次启动时恢复。

  • onDestory// 清理资源,释放内存,取消监听器

在 Activity 被销毁之前调用,可能是因为系统需要回收内存,或者用户退出。用于彻底清理 Activity,释放所有资源,例如取消注册的监听器、关闭线程或清理后台任务。onDestroy() 在生命周期的结束阶段调用,意味着 Activity 即将被完全回收。

  • onRestart// 重新加载资源或状态,更新界面

当 Activity 从“停止”状态重新启动,进入可见状态之前调用。适合在重新启动 Activity 前做准备工作,例如重新加载数据或刷新界面。通常会在 onStart() 之前调用,是 Activity 从不可见到可见的过渡状态。

上述图片中,存在三个周期:

  1. 整个的生命周期:onCreate() → onStart() → onResume() → Activity running → onPause() → onStop() → onDestory()
  2. 可见的生命周期:onStart() → onResume() → Activity running → onPause() → onStop() → onRestart()
  3. 前台的生命周期:onResume() → Activity running → onPause()

Activity 栈

Activity栈(Activity Stack)是 Android 系统中用于管理 Activity 之间导航和生命周期的重要机制。它以栈的形式维护应用的不同 Activity,使得用户可以通过返回操作逐步返回到之前的 Activity。

四种状态

  • 运行状态(Active/Running)

定义:当 Activity 位于栈顶并显示在前台时,它处于“运行”状态。

特点:用户可以直接与之交互,Activity 的界面可见且拥有焦点。

生命周期:处于 onResume() 方法之后,直到 Activity 失去焦点或被其他 Activity 覆盖。

  • 暂停状态(Paused)

定义:当 Activity 仍然部分可见,但失去焦点时,它进入“暂停”状态。

特点:虽然 Activity 部分显示在前台,但由于被半透明的 Activity(如对话框)或新 Activity 部分覆盖,用户无法与之交互。

生命周期:调用 onPause() 方法,但没有调用 onStop(),这意味着系统保留了 UI 和数据状态。

  • 停止状态(Stopped)

定义:当 Activity 完全不可见且被其他 Activity 覆盖时,它进入“停止”状态。

特点:Activity 完全离开了前台,但系统会保留它在内存中的状态(如用户输入的数据)。

生命周期:调用 onStop() 方法。Activity 在后台待命,可以被用户通过返回键或任务管理器重新唤醒。

  • 销毁状态(Destroyed)

定义:当 Activity 被系统回收或用户退出时,Activity 进入“销毁”状态。

特点:Activity 被彻底清理,系统会调用 onDestroy() 方法,释放所有资源和数据。

生命周期:调用 onDestroy() 方法后,Activity 完全消失,无法恢复状态。若用户重新打开该 Activity,会重新创建。

活动的启动模式

  • standard

这是默认的启动模式。每次启动一个 Activity 时,都会创建该 Activity 的新实例,并将其推入当前任务栈(task stack)中。在 standard 模式(即默认情况)下,每当启动一个新的活动,它就会在返回栈中入栈,并处于栈顶的位置。对于使用 standard 模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。默认无需指定 launchMode,如果不设置 launchMode,系统会自动采用 standard 模式。

  • singleTop

当启动一个 Activity 时,如果该 Activity 已经位于栈顶,则不会创建新的实例,而是重用栈顶的实例。否则,创建新的实例并将其压入栈中。如果栈顶已有目标 Activity 实例,则重用该实例并调用其 onNewIntent() 方法;否则,创建新的 Activity 实例。适用于需要避免重复创建 Activity 实例的场景,尤其是在不希望多个相同页面堆积在栈中的情况。例如,某些页面如新闻列表页,每次点击一个项目时,我们希望直接跳转到目标页面,而不希望栈中堆积多个相同的页面。

Manifest 声明

1
<activity android:name=".MainActivity" android:launchMode="singleTop" />
  • singleTask

该模式启动的 Activity 会在一个新的任务栈中运行(如果没有其他 Activity 实例与其重叠)。如果栈中已经存在该 Activity 的实例,系统会销毁栈中该 Activity 上面的所有 Activity,并重新将该 Activity 实例带到前台。当启动目标 Activity 时,如果该 Activity 已经存在于任务栈中,系统将删除栈中该 Activity 之上的所有 Activity,并将目标 Activity 带到前台。新的任务栈会包含这个 Activity 的实例。适用于需要单一实例且确保全局唯一的 Activity,常用于应用的主界面或者登录界面。它有助于控制多个页面之间的导航,避免重复的 Activity 实例。

Manifest 声明

1
<activity android:name=".MainActivity" android:launchMode="singleTask" />
  • singleInstance

这种模式与 singleTask 类似,不同之处在于该 Activity 会在一个独立的任务栈中运行,而且任务栈中只能包含一个 Activity 实例。即使栈中已经有该 Activity 实例,也会创建新的任务栈,并且该栈只能包含一个 Activity 实例。每次启动该 Activity 时,它都会创建一个新的任务栈,并且该栈只包含该 Activity 实例。其他所有 Activity 都不能和该 Activity 实例共享一个栈。通常用于特殊场景,例如需要独立管理的 Activity(如应用中的设置界面、系统界面等),确保该 Activity 始终只有一个实例并运行在独立的栈中。

在这种模式下会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活
动,都共用的同一个返回栈

Intent

Intent 是一个用于在应用组件之间传递信息的对象。Intent 可以启动 Activity、Service,甚至可以用于广播传递数据。它是 Android 系统中实现组件间通信的核心机制。

显示 Intent

显式指定目标组件的名称。常用于应用内部组件之间的调用,比如从一个 Activity 启动另一个 Activity。

使用方法

首先按照之前的方法再创建一个 activity,仍然还是右击 com.example.activitytest 包 →New→Activity→Empty view Activity, 会弹出一个创建
活动的对话框, 我们这次将活动命名为 SecondActivity, 并勾选 Generate Layout File, 给布局文件起名为 second_layout, 但不要勾选 Launcher Activitv 选项,

我们添加一个 button2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SecondActivity">
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button 2"
/>
</androidx.constraintlayout.widget.ConstraintLayout>

SecondActivity 已经帮我们生成好了一部分代码,当然,要记得任何一个活动创建后都要在 AndroidManifest.xml 中注册,不过 Android Studio 已经帮我们自动完成了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" >

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Nactivity"
tools:targetApi="31" >
<activity
android:name=".SecondActivity"
android:exported="false"
android:label="This is my SecondActivity"
/>
<activity
android:name=".FirstActivity"
android:exported="true"
android:label="This is my FirstActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

由于 SecondActivity 不是主活动,所以不用 标签设置启动,现在我们只差一步了:如何启动第二个活动了,这里就需要 Intent 了。

Intent 有多个构造函数的重载,其中有一个是 Intent(Context packageContext, Class <?> cls)。这个函数接受两个参数,第一个参数是要求提供一个启动活动的上下文,第二个参数 Class 则是指定想要启动的目标活动,由于 Intent 只是指明当前组件想要执行的动作,属于意图,所以我们还得使用 startActivity 方法,这个方法是专门用于启动活动的,它的参数是 intent,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.example.activitytest;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class FirstActivity extends AppCompatActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main,menu);
return true;
}

@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.add_item:
Toast.makeText(this, "You click Add", Toast.LENGTH_SHORT).show();
break;
case R.id.remove_item:
Toast.makeText(this, "You click Remove", Toast.LENGTH_SHORT).show();
break;
default:
}
return true;
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
Button button1=findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(FirstActivity.this, "You Click The Button!", Toast.LENGTH_SHORT).show();
Intent intent =new Intent(FirstActivity.this,SecondActivity.class);
startActivity(intent);
}
});
}
}

当我们启动 App 后,点击 Button1 会启动 SecondActivity,当我们再按 back 键后,就会销毁 SecondActivity,退回到 FirstActivity。由于 Intent 的意图非常明显,所以我们称之为显式 Intent。

隐式 Intent

不指定目标组件的名称,而是通过 ActionCategoryData 来描述要执行的操作。系统会根据 Intent 的描述来查找能够响应此 Intent 的组件。常用于调用其他应用的功能,如打开浏览器、拨打电话等。

createChooser

如果有多个应用响应隐式 Intent,则系统会弹出对话框,让用户选择要使用的应用,用户也可以将某个应用设置为该操作的默认选项。如果想让用户无法选择用于操作的应用,而强制使用某个应用响应该操作时,可以使用强制选择器:

Android 提供了 Intent.createChooser() 方法,用来创建强制选择器。该方法返回一个 Chooser Intent,强制系统显示选择器对话框。

1
2
3
4
5
6
7
Intent sendIntent = new Intent(Intent.ACTION_SEND);//创建了一个 Intent 对象 sendIntent,并设置操作类型为 ACTION_SEND,表示我们想要分享内容
sendIntent.setType("text/plain");//
sendIntent.putExtra(Intent.EXTRA_TEXT, "Hello! This is a message.");

// 使用 createChooser() 强制显示选择器
Intent chooser = Intent.createChooser(sendIntent, "请选择应用进行分享");//将 sendIntent 作为参数传入 createChooser()方法,同时指定选择器的标题(如 "请选择应用进行分享")
startActivity(chooser);//使用 startActivity(chooser)启动选择器。即使系统中只有一个应用可以处理该 Intent,这个方法仍然会显示选择器对话框,让用户确认使用哪个应用。

属性

Intent 在 Android 中是一个用于在不同应用组件之间传递数据的关键对象。通过 Intent 的属性,可以详细描述要执行的操作,并传递执行该操作所需的数据。

  • Action

作用Action 属性用于描述 Intent 的目的,指示要执行的操作类型。比如查看网页、拨打电话、发送短信等。

使用Action 通常是一个字符串常量,系统和应用可以通过它来确定要执行的操作。

action 常量地址:https://developer.android.google.cn/guide/components/intents-common?hl = zh-cn

  • Data

作用Data 属性用于指定要操作的数据的 URI。例如,如果 ActionACTION_VIEWData 可以指定一个网页的 URI 或者图片的 URI。

使用:通过 setData() 方法设置数据。DataAction 配合使用,描述了该 Intent 将要处理的数据。

  • Category

作用Category 提供关于 Intent 额外的执行信息,指定该 Intent 的目标类型。例如,可以指定该 Intent 的类型是启动器应用还是浏览器。

使用:通过 addCategory(String category) 方法添加 Category。一般来说,一个 Intent 可以包含多个 Category

  • Component

作用Component 用于指定 Intent 的目标组件。通过该属性,可以显式指定要启动的 Activity 或 Service。

使用:通过 setComponent() 方法设置,或者直接在构造函数中传入目标组件。

  • Extras

作用Extras 用于在 Intent 中存储附加数据,是键值对(key-value)形式的附加信息。常用于在组件之间传递复杂数据,如字符串、布尔值、对象等。

使用:通过 putExtra() 方法添加数据,通过 getExtra() 方法获取数据。

  • Flags

作用Flags 用于描述 Intent 的行为和启动模式。通过设置不同的标志,可以控制 Intent 的启动方式,比如是否创建新任务栈、是否清除任务栈等。

使用:通过 addFlags() 方法添加标志。

  • Type

作用Type 指定数据的 MIME 类型,用于告诉系统如何解释 Intent 中携带的数据。与 Data 结合使用时非常有用,比如指定要打开的数据类型。

使用:通过 setType(String type) 方法设置。

Intent 过滤器

1

Intent 过滤器Intent Filter)是用于定义组件(Activity、Service、BroadcastReceiver)可以响应哪些 Intent 的机制。它位于 AndroidManifest.xml 中,用来描述组件对某些特定 Intent 的响应能力,从而让系统知道哪些组件能够处理给定的 Intent。

通过设置 Intent 过滤器,应用可以实现组件之间的灵活交互,甚至支持隐式 Intent,从而允许其他应用调用该组件的功能。

Intent Filter 的组成

一个 Intent 过滤器主要由以下三部分组成:<action><category><data>,这三部分共同定义了该组件可以处理哪些 Intent。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<activity android:name="ShareActivity">
<!-- This activity handles "SEND" actions with text data -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
<!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<action android:name="android.intent.action.SEND_MULTIPLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/vnd.google.panorama360+jpg"/>
<data android:mimeType="image/*"/>
<data android:mimeType="video/*"/>
</intent-filter>
</activity>
  • <action>

作用<action> 指定了组件能够响应的操作类型。Action 是一个字符串常量,用来标识该 Intent 的基本目的。

Intent 只能设置一个 action,但一个 Intent 过滤器可以声明多个 action。只要 Intent 中的 action 与 Intent 过滤器的某一项 action 匹配,就可以通过 action 测试。

  • <category>

作用<category> 提供关于 Intent 的额外信息,用于进一步描述组件可以处理的特定类型的 Intent。对于大多数 Intent 过滤器,必须包含 CATEGORY_DEFAULT,它表示该组件能够处理由系统启动的 Intent

Intent 可以包含多项 category,Intent 过滤器也可以包含多项 category。Intent 中的每项 category 必须在 Intent 过滤器中都有对应项,才能通过 category 测试。

  • <data>

作用<data> 用于描述组件能够处理的数据类型,包括 URI 和 MIME 类型的组合。<data> 标签可以设置数据的 schemehostportpath 等参数,用于更加精确地过滤数据。

URI 匹配规则

URI 的格式为 <scheme>://<host>:<port>/<path>,上述每个属性均为可选,但存在线性依赖关系:

  • 如果未指定 scheme,则会忽略 host。
  • 如果未指定 host,则会忽略 port。
  • 如果未指定 scheme 和 host,则会忽略 path

Intent Filter 的匹配规则

系统在查找可以处理 Intent 的组件时,会通过以下三步进行匹配:

  1. Action 匹配:Intent 的 action 和过滤器中的 <action> 必须匹配。
  2. Category 匹配:Intent 的 category 和过滤器中的 <category> 必须完全匹配。Intent 中可能有多个 Category,而 Intent Filter 的所有 Category 都必须在 Intent 中包含。
  3. Data 匹配:Intent 的 data 和过滤器中的 <data> 部分必须匹配。系统会根据 scheme、host、port、path、mimeType 等属性匹配数据。

Intent 数据传递

在 Android 中,Intent 用于在应用的不同组件(如 ActivityServiceBroadcastReceiver)之间传递数据。数据传递是 Intent 的一项重要功能,它允许在不同的组件之间共享信息,从而实现灵活的组件交互。Intent 可以通过 Extras 属性以键值对的形式传递各种类型的数据。

Intent 数据传递的方式

主要有两种数据传递方式:

  1. 基本数据类型传递:直接通过 putExtra 方法传递单个数据项,如字符串、整型、布尔值等。
  2. 复杂数据类型传递:通过传递 BundleSerializable 对象、Parcelable 对象等,进行更复杂的数据传递。

Intent 数据回传

在一个 Activity 启动另一个 Activity,然后接收返回的数据。通常使用 startActivityForResult() 方法启动目标 Activity,并在返回时通过 onActivityResult() 方法获取结果数据。

从 Android 11(API Level 30)开始,谷歌推荐使用 ActivityResult API 代替 startActivityForResult(),更安全和易于管理。

待定 Intent

“待定 Intent”(PendingIntent)是一种特殊的 Intent,允许另一个应用或系统组件在特定情况下代替应用程序执行一个 IntentPendingIntent 通常用于延迟执行操作。

PendingIntent 的相关方法

  • getActivity():返回一个启动 Activity 的 PendingIntent。
  • getService():返回一个启动 Service 的 PendingIntent。
  • getBroadcast():返回一个发送广播的 PendingIntent。
  • cancel():取消当前的 PendingIntent。
  • send():发送当前的 PendingIntent。

评论