第二个 Android 11 开发者预览版现已推出,快来测试并分享您的反馈吧

“最近使用的应用”屏幕

最近使用的应用屏幕(也称为概览屏幕、近期任务列表或最近用过的应用)是一个系统级界面,上面列出了最近访问过的 Activity任务。用户可以浏览该列表并选择要恢复的任务,也可以通过滑开操作将任务从列表中移除。Android 5.0(API 级别 21)引入了以文档为中心的模型,也就是说,如果同一 Activity 的多个实例包含不同的文档,它们可能会在最近使用的应用屏幕中显示为任务。比如说,Google 云端硬盘的几个 Google 文档可能各自都有一个任务。每个文档都会在最近使用的应用屏幕中显示为任务。

图 1. 最近使用的应用屏幕上显示三个 Google 云端硬盘文档,每个文档都表示为单独的任务。

另一个常见的例子是当用户使用浏览器时,点按分享 > Gmail。系统会显示 Gmail 应用的写邮件屏幕。此时点按最近使用的应用按钮会显示 Chrome 和 Gmail 作为单独的任务运行。在较低版本的 Android 中,所有 Activity 都显示为单个任务,因此返回按钮是唯一的导航方式。图 2 对比显示了最近使用的应用屏幕在 Android 5.0 及更高版本和较低平台版本上的外观。左侧图片所示为 Android 5.0 及更高版本的屏幕,右侧图片所示为较低 Android 版本中的屏幕。

Android 5.0 之前版本与“最近使用的应用”屏幕的早期视图

图 2. Android 5.0 及更高版本(左)和 Android 5.0(右侧)以下版本中的最近使用的应用屏幕。

通常情况下,您应允许系统定义您的任务和 Activity 在最近使用的应用屏幕中的表示方式,并且您无需修改此行为。不过,您的应用可以确定 Activity 在最近使用的应用屏幕中的显示方式和时间。您可以使用 ActivityManager.AppTask 类来管理任务,并使用 Intent 类的 Activity 标记来指定在最近使用的应用屏幕中添加或移除 Activity 的时间。此外,您还可以使用 <activity> 属性在清单中设置行为。

将任务添加到“最近使用的应用”屏幕

使用 Intent 类的标记添加任务,您可以更好地控制在最近使用的应用屏幕中打开或重新打开文档的方式和时间。当您使用 <activity> 属性时,您可以选择始终在新任务中打开文档或重复使用文档的现有任务。

使用 Intent 标记添加任务

为 Activity 创建新文档时,您可以调用 startActivity() 方法并向其传递到启动该 Activity 的 intent。要插入逻辑断点,以便系统将您的 Activity 视为最近使用的应用屏幕中的新任务,请将 FLAG_ACTIVITY_NEW_DOCUMENT 标记传入启动该 Activity 的 IntentaddFlags() 方法。

注意FLAG_ACTIVITY_NEW_DOCUMENT 标记取代了 FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET 标记,后者自 Android 5.0(API 级别 21)起已弃用。

如果您在创建新文档时设置了 FLAG_ACTIVITY_MULTIPLE_TASK 标记,则系统始终会以目标 Activity 为根来创建新任务。此设置支持同一文档在多个任务中打开。以下代码演示了主 Activity 如何执行此操作:

Kotlin

    fun createNewDocument(view: View) {
        val newDocumentIntent = newDocumentIntent()
        if (useMultipleTasks) {
            newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
        }
        startActivity(newDocumentIntent)
    }

    private fun newDocumentIntent(): Intent =
            Intent(this, NewDocumentActivity::class.java).apply {
                addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT or
                        android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)
                putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, documentCounter++)
            }

    

Java

DocumentCentricActivity.java

    public void createNewDocument(View view) {
          final Intent newDocumentIntent = newDocumentIntent();
          if (useMultipleTasks) {
              newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
          }
          startActivity(newDocumentIntent);
      }

      private Intent newDocumentIntent() {
          boolean useMultipleTasks = checkbox.isChecked();
          final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class);
          newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
          newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, documentCounter++);
          return newDocumentIntent;
      }

    }
    

注意:使用 FLAG_ACTIVITY_NEW_DOCUMENT 标记启动的 Activity 必须在清单中设置 android:launchMode="standard" 属性值(默认值)。

当主 Activity 启动一个新 Activity 时,系统会在现有任务中进行搜索,看是否任务的 intent 与该 Activity 的 intent 组件名称和 Intent 数据匹配。如果未找到该任务,或 intent 包含 FLAG_ACTIVITY_MULTIPLE_TASK 标记,那么将以该 Activity 为根创建一个新任务。如果找到该任务,则会将其带到最前端,并将新 intent 传递到 onNewIntent()。新 Activity 获取 Intent,并在最近使用的应用屏幕中创建新文档,如下例所示:

Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_new_document)
        documentCount = intent
                .getIntExtra(DocumentCentricActivity.KEY_EXTRA_NEW_DOCUMENT_COUNTER, 0)
        documentCounterTextView = findViewById(R.id.hello_new_document_text_view)
        setDocumentCounterText(R.string.hello_new_document_counter)
    }

    override fun onNewIntent(newIntent: Intent) {
        super.onNewIntent(newIntent)
        /* If FLAG_ACTIVITY_MULTIPLE_TASK has not been used, this Activity
        will be reused. */
        setDocumentCounterText(R.string.reusing_document_counter)
    }
    

Java

NewDocumentActivity.java

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_new_document);
        documentCount = getIntent()
                .getIntExtra(DocumentCentricActivity.KEY_EXTRA_NEW_DOCUMENT_COUNTER, 0);
        documentCounterTextView = (TextView) findViewById(
                R.id.hello_new_document_text_view);
        setDocumentCounterText(R.string.hello_new_document_counter);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        /* If FLAG_ACTIVITY_MULTIPLE_TASK has not been used, this activity
        is reused to create a new document.
         */
        setDocumentCounterText(R.string.reusing_document_counter);
    }
    

使用 Activity 属性添加任务

Activity 还可以在其清单中使用 <activity> 属性 android:documentLaunchMode 指定始终启动到新任务。该属性具有四个值,在用户使用应用打开文档时分别会产生以下效果:

"intoExisting"
Activity 重复使用文档的现有任务。这与设置了 FLAG_ACTIVITY_NEW_DOCUMENT 标记但没有设置 FLAG_ACTIVITY_MULTIPLE_TASK 标记的效果相同,如上文使用 Intent 标记添加任务所述。
"always"
Activity 会为文档创建新任务,即使文档已打开也一样。使用该值与同时设置了 FLAG_ACTIVITY_NEW_DOCUMENTFLAG_ACTIVITY_MULTIPLE_TASK 标记的效果相同。
"none"
Activity 不会为文档创建新任务。最近使用的应用屏幕会以默认方式处理 Activity:它会显示应用的单个任务,该任务是从用户上次调用的任何 Activity 恢复的。
"never"
Activity 不会为文档创建新任务。设置该值会替换 FLAG_ACTIVITY_NEW_DOCUMENTFLAG_ACTIVITY_MULTIPLE_TASK 标记的行为(如果在 intent 中设置了任意一个),而且最近使用的应用屏幕会显示应用的单个任务,该任务是从用户上次调用的任何 Activity 恢复的。

注意:如果值不是 nonenever,必须使用 launchMode="standard" 定义 Activity。如果未指定此属性,会使用 documentLaunchMode="none"

移除任务

默认情况下,当相关的 Activity 完成时,文档任务会自动从最近使用的应用屏幕中移除。您可以使用 ActivityManager.AppTask 类、Intent 标记或 <activity> 属性来替换此行为。

<activity> 属性 android:excludeFromRecents 设置为 true,即可始终将任务从最近使用的应用屏幕中完全排除。

<activity> 属性 android:maxRecents 设置为一个整数,即可设置您的应用可在最近使用的应用屏幕中包含的最大任务数。默认值为 16。一旦达到最大任务数,最早使用的任务将从最近使用的应用屏幕中移除。android:maxRecents 最大值为 50(内存较低的设备上为 25);小于 1 的值无效。

使用 AppTask 类移除任务

对于在最近使用的应用屏幕中创建新任务的 Activity,您可以通过调用 finishAndRemoveTask() 方法来指定何时应移除任务并完成与该任务相关联的所有 Activity。

Kotlin

    fun onRemoveFromOverview(view: View) {
        // It is good pratice to remove a document from the overview stack if not needed anymore.
        finishAndRemoveTask()
    }
    

Java

NewDocumentActivity.java

    public void onRemoveFromRecents(View view) {
        // The document is no longer needed; remove its task.
        finishAndRemoveTask();
    }
    

注意:使用 finishAndRemoveTask() 方法会替换 FLAG_ACTIVITY_RETAIN_IN_RECENTS 标记的使用,如下文所述。

保留已完成的任务

如果您即使在任务的 Activity 已完成后也希望在最近使用的应用屏幕中保留它,请将 FLAG_ACTIVITY_RETAIN_IN_RECENTS 标记传入启动该 Activity 的 Intent 的 addFlags() 方法。

Kotlin

    private fun newDocumentIntent() =
            Intent(this, NewDocumentActivity::class.java).apply {
                addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT or
                        android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)
                putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, getAndIncrement())
            }
    

Java

DocumentCentricActivity.java

    private Intent newDocumentIntent() {
        final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class);
        newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
          android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS);
        newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, getAndIncrement());
        return newDocumentIntent;
    }
    

要达到同样的效果,请将 <activity> 属性 android:autoRemoveFromRecents 设置为 false。文档 Activity 的默认值为 true,常规 Activity 的默认值为 false。使用此属性会替换上文所述的 FLAG_ACTIVITY_RETAIN_IN_RECENTS 标记。

更多示例代码

要下载有关以文档为中心的应用的示例应用,请参阅 DocumentCentricRecents 示例Android DocumentCentricRelinquishIdentity 示例