activity 简介

Activity 类是 Android 应用的关键组件,而 Activity 的启动和组合方式则是该平台应用模型的 基本组成部分。在编程范式中,应用是通过 a main 方法启动的,而 Android 系统与此不同,它会调用与其生命周期特定阶段相对应的特定回调方法来启动 Activity 实例中的代码。

本文介绍了 Activity 的概念,并提供了有关如何使用 Activity 的简要说明。如需详细了解有关设计应用架构的最佳实践,请参阅 应用架构指南

Activity 的概念

移动应用体验与桌面体验的不同之处在于,用户与应用的互动并不总是在同一位置开始, 而是经常以不确定的方式开始。例如,如果您从主屏幕打开电子邮件应用,可能会看到电子邮件列表, 如果您通过社交媒体应用启动电子邮件应用,则可能会直接进入电子邮件应用的邮件撰写界面。

The Activity 类旨在促进这种范式。当一个应用调用另一个应用时,调用方应用会调用另一个应用中的 Activity,而不是整个应用。通过这种方式,Activity 充当了应用与用户互动的入口点。您可以将 Activity 实现为 Activity 类的子类。

Activity 提供窗口供应用在其中绘制界面。此窗口通常会填满屏幕,但也可能比屏幕小,并浮动在其他窗口上面。

通常,应用中的一个 Activity 会被指定为主 Activity,这是用户启动应用时出现的第一个屏幕。在现代 Compose 应用中,这是唯一必要的 Activity,因为它在单 Activity 架构中托管可组合项,而不是拥有视图层次结构。Activity 中的可组合项托管多个导航目的地,而不是应用为屏幕提供多个 Activity。

要在应用中使用 Activity,您必须在应用的清单中注册关于 Activity 的信息,并且最好了解 Activity 的生命周期。本文的其余部分将介绍这些主题。

配置清单

要使应用能够使用 Activity,您必须在清单中声明 Activity 及其特定属性。

声明 Activity

如需声明 Activity,请打开清单文件,然后添加一个 <activity> 元素作为 <application> 元素的子元素。例如:

<manifest ... >
  <application ... >
      <activity android:name=".ExampleActivity" />
      ...
  </application ... >
  ...
</manifest >

此元素唯一的必要属性是 android:name,该属性用于 指定 Activity 的类名称。您也可以添加用于定义标签、图标或界面主题等 Activity 特征的属性。如需详细了解上述及其他属性,请参阅 <activity> 元素参考文档。

声明 intent 过滤器

Intent 过滤器 是 Android 平台的一项非常强大的功能。它们 不仅能够根据显式 请求启动 Activity,还能根据隐式请求启动 Activity。例如,显式请求可能会告诉系统“在 Gmail 应用中启动‘发送电子邮件’Activity”, 而隐式请求可能会告诉系统“在任何能够完成此工作的 Activity 中启动‘发送电子邮件’屏幕”。当系统界面询问用户使用哪个应用来执行任务时,这就是 intent 过滤器在起作用。

您可以在 <activity> 元素中声明 <intent-filter> 属性,以利用此功能。此元素的定义包括一个<action>元素,以及可选的<category>元素和/或<data>元素。这些元素组合在一起,可以指定 Activity 能够响应的 intent 类型。例如,以下代码段展示了如何配置一个 Activity,该 Activity 可以发送文本数据和电子邮件,并接收来自其他 Activity 的请求以执行此操作:

<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
   <intent-filter>
        <action android:name="android.intent.action.SENDTO" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="mailto" />
    </intent-filter>
</activity>

在此示例中,<action> 元素指定此 Activity 发送 数据。将 <category> 元素声明为 DEFAULT 可使 Activity 能够接收启动请求。<data> 元素指定此 Activity 可以发送的数据类型。以下代码段展示了如何调用上述 Activity 来撰写电子邮件:

fun composeEmail(addresses: Array<String>, subject: String) {
    val intent = Intent(Intent.ACTION_SENDTO).apply {
        data = Uri.parse("mailto:") // Only email apps handle this.
        putExtra(Intent.EXTRA_EMAIL, addresses)
        putExtra(Intent.EXTRA_SUBJECT, subject)
    }
    if (intent.resolveActivity(packageManager) != null) {
        startActivity(intent)
    }
}

如果您打算构建一个独立的应用,不允许其他应用激活其 Activity,则不需要任何其他 intent 过滤器。您不想让其他应用访问的 Activity 不应包含 intent 过滤器,您可以自己使用显式 intent 启动它们。如需详细了解 Activity 如何响应 intent,请参阅 intent 和 intent 过滤器

处理传入的 intent

以下示例展示了在处理多种 intent 类型(单条文本分享、单张图片和多张图片数组)时管理 activity 生命周期的模式。通过将这些不同的输入路由到集中式 handleIntent函数,可以确保ACTION_SENDACTION_SEND_MULTIPLE操作都得到正确解析并委托给 ViewModel,以进行响应式界面更新。

class ExampleActivity : ComponentActivity() {
  private val viewModel: MyViewModel by viewModels()

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    handleIntent(intent)
    setContent {
      ComposeApp(viewModel)
    }
  }

  override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    setIntent(intent)
    handleIntent(intent)
  }

  private fun handleIntent(intent: Intent?) {
    when (intent?.action) {
      Intent.ACTION_SEND -> {
        if ("text/plain" == intent.type) {
          intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
            viewModel.handleText(it) // Update UI to reflect text being shared
          }
        } else if (intent.type?.startsWith("image/") == true) {
          (intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))?.let {
            viewModel.handleImage(it) // Update UI to reflect image being shared
          }
        }
      }

      Intent.ACTION_SEND_MULTIPLE -> {
          if (intent.type?.startsWith("image/") == true) {
              intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)?.let {
                  viewModel.handleMultipleImages(it) // Update UI to reflect multiple images being shared
              }
          } else {
              // Handle other types
          }
      }

      else -> {
          // Handle other intents
      }
    }
  }
}

声明权限

您可以使用清单的 <activity> 标记来控制哪些应用可以启动 特定 Activity。父 Activity 和子 Activity 必须在其清单中具有相同的权限,前者才能启动后者。如果您为父 Activity 声明了 <uses-permission> 元素,则每个子 Activity 都必须具有匹配的 <uses-permission> 元素。

例如,假设您的应用想要使用一个名为 SocialApp 的应用在社交媒体上分享文章,则 SocialApp 本身必须定义调用它的应用所需具备的权限:

<manifest>
<activity android:name="...."
   android:permission="com.google.socialapp.permission.SHARE_POST"

/>

然后,为了能够调用 SocialApp,您的应用必须匹配 SocialApp 清单中设置的权限集:

<manifest>
   <uses-permission android:name="com.google.socialapp.permission.SHARE_POST" />
</manifest>

如需详细了解权限和安全性,请参阅安全 核对清单

管理 Activity 生命周期

一个 Activity 在其生命周期中会经历多种状态。您可以使用一系列回调来处理状态之间的转换。以下部分将介绍这些回调。在 Compose 应用中,不建议直接挂钩到这些回调。而是使用 Lifecycle API 来观察状态变化。如需了解详情,请参阅将 Lifecycle 与 Compose集成。

onCreate

您必须实现此回调,该回调会在系统创建 Activity 时触发。您的实现应该初始化 Activity 的基本组件:例如,您的应用应该在此处创建视图并将数据绑定到列表。

在 Compose 应用中,使用此回调通过 setContent 设置宿主可组合项,如下所示:

class MyActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Text(text = stringResource(id = R.string.greeting))
        }
    }
}

onCreate 完成后,下一个回调始终是 onStart

onStart

onCreate 退出后,Activity 将进入“已启动”状态,并对用户可见。此回调包含 Activity 进入前台与用户进行互动之前的最后准备工作。

onResume

系统会在 Activity 开始与用户互动之前调用此回调。此时,该 Activity 位于 Activity 堆栈的顶部,并会捕获所有用户输入。应用的大部分核心功能都是在 onResume方法中实现的。

The onPause 回调始终跟随 onResume

onPause

当 Activity 失去焦点并进入 “已暂停”状态时,系统就会调用 onPause。例如,当用户点按“返回”或“最近使用的应用”按钮时,就会出现此状态。当系统为您的 Activity 调用 onPause 时,从技术上来说,这意味着您的 Activity 仍然部分可见,但大多数情况下,这表明用户正在离开该 Activity,该 Activity 很快将进入“已停止”或“已恢复”状态。

如果用户希望界面继续更新,则处于“已暂停”状态的 Activity 也可以继续更新界面。例如,显示导航地图屏幕或播放媒体播放器的 Activity 就属于此类 Activity。即使此类 Activity 失去了焦点,用户仍希望其界面继续更新。

不应 使用 onPause 来保存应用或用户数据、进行 网络呼叫或执行数据库事务。如需了解有关保存 数据的信息,请参阅保存和恢复暂时性界面状态

onPause 执行完毕后,下一个回调为 onStoponResume,具体取决于 Activity 进入“已暂停”状态后发生的情况。

onStop

当 Activity 对用户不再可见时,系统会调用 onStop。出现这种情况的原因可能是 Activity 被销毁,新的 Activity 启动,或者现有的 Activity 正在进入“已恢复”状态并覆盖了已停止的 Activity。在所有这些情况下,停止的 Activity 都将完全不再可见。

系统调用的下一个回调将是 onRestart(如果 Activity 重新与用户互动)或者 onDestroy(如果此 Activity 彻底终止)。

onRestart

当处于“已停止”状态的 Activity 即将重启时,系统就会调用此回调。onRestart 会恢复 Activity 停止时的状态。

此回调始终跟随 onStart

onDestroy

系统会在销毁 Activity 之前调用此回调。

此回调是 Activity 接收的最后一个回调。onDestroy 通常 实现是为了确保在销毁 Activity 或包含该 Activity 的进程时释放该 Activity 的所有资源。

本部分只是简要地介绍了该主题。如需详细了解 Activity 生命周期及其回调,请参阅 The activity lifecycle