最近屏幕,也称为概览屏幕、最近任务列表或最近应用屏幕,是一种系统级 UI,用于列出最近访问的 Activity 和 任务。用户可以浏览列表、选择任务以恢复,或通过滑动方式从列表中移除任务。
最近屏幕使用 以文档为中心 的模型(在 Android 5.0(API 级别 21)中引入),其中包含不同文档的同一 Activity 的多个实例可以作为任务显示在最近屏幕中。例如,Google 云端硬盘可能为每个 Google 文档分配一个任务。每个文档都会显示为最近屏幕中的一个任务。
另一个常见示例是,当用户使用浏览器时,他们依次点按 分享 > Gmail。Gmail 应用的 撰写 屏幕随即显示。此时点按最近屏幕按钮会显示 Chrome 和 Gmail 正在作为独立任务运行。
通常,您可以让系统定义您的任务和 Activity 在最近屏幕中的显示方式。您无需修改此行为。但是,您的应用可以确定 Activity 何时以及如何显示在最近屏幕中。
ActivityManager.AppTask
类可让您管理任务,而 Intent
类的 Activity 标志可让您指定何时将 Activity 添加或从最近屏幕中移除。此外,<activity>
属性可让您在清单中设置行为。
将任务添加到最近屏幕
使用 Intent
类的标志来添加任务,可让您更好地控制文档在最近屏幕中打开或重新打开的时间和方式。当您使用 <activity>
属性时,您可以选择是始终在新任务中打开文档,还是为文档重用现有任务。
使用 Intent 标志添加任务
当您为 Activity 创建新文档时,您需要调用 startActivity()
方法,并向其传递启动 Activity 的 intent。要插入逻辑中断,以便系统将您的 Activity 视为最近屏幕中的新任务,请在启动 Activity 的 Intent
的 addFlags()
方法中传递 FLAG_ACTIVITY_NEW_DOCUMENT
标志。
如果您在创建新文档时设置 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
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; } }
当主 Activity 启动新 Activity 时,系统会搜索现有任务,查找与该 Activity 的 intent 组件名称和 intent 数据匹配的任务。如果未找到任务,或者 intent 包含 FLAG_ACTIVITY_MULTIPLE_TASK
标志,则会创建一个以该 Activity 为根的新任务。
如果系统找到一个与 intent 组件名称和 intent 数据匹配的任务,它会将该任务带到前台,并将新 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
@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_DOCUMENT
和FLAG_ACTIVITY_MULTIPLE_TASK
标志效果相同。 none
- 该 Activity 不会为文档创建新任务。最近屏幕会像默认情况下一样处理该 Activity。它会为应用显示单个任务,该任务会从用户上次调用的任何 Activity 中恢复。
never
- 该 Activity 不会为文档创建新任务。设置此值会覆盖
FLAG_ACTIVITY_NEW_DOCUMENT
和FLAG_ACTIVITY_MULTIPLE_TASK
标志的行为。如果 intent 中设置了这些标志中的任何一个,并且最近屏幕为应用显示单个任务,则它会从用户上次调用的任何 Activity 中恢复。
移除任务
默认情况下,文档任务在其 Activity 完成时会自动从最近屏幕中退出。您可以使用 ActivityManager.AppTask
类、Intent
标志或 <activity>
属性来覆盖此行为。
您可以始终通过将 <activity>
属性 android:excludeFromRecents
设置为 true
来完全将任务从最近屏幕中排除。
您可以通过将 <activity>
属性 android:maxRecents
设置为整数值,来设置应用可以在最近屏幕中包含的最大任务数。当达到最大任务数时,最近最少使用的任务会从最近屏幕中消失。默认值为 16,最大值为 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
public void onRemoveFromRecents(View view) { // The document is no longer needed; remove its task. finishAndRemoveTask(); }
保留已完成的任务
如果您希望在最近屏幕中保留任务,即使其 Activity 已完成,请在启动 Activity 的 intent 的 addFlags()
方法中传递 FLAG_ACTIVITY_RETAIN_IN_RECENTS
标志。
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
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
标志。
启用最近 URL 共享(仅限 Pixel)
在运行 Android 12 或更高版本的 Pixel 设备上,用户可以直接从最近屏幕共享最近浏览过的网页内容的链接。在应用中访问内容后,用户可以滑动到最近屏幕,找到他们查看内容的应用程序,然后点按链接按钮以复制或分享 URL。
任何应用都可以通过提供网络 UI 并覆盖 onProvideAssistContent()
来为用户启用最近链接,如以下示例所示:
Kotlin
class MainActivity : AppCompatActivity() { protected fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } fun onProvideAssistContent(outContent: AssistContent) { super.onProvideAssistContent(outContent) outContent.setWebUri(Uri.parse("https://example.com/myCurrentPage")) } }
Java
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void onProvideAssistContent(AssistContent outContent) { super.onProvideAssistContent(outContent); outContent.setWebUri(Uri.parse("https://example.com/myCurrentPage")); } }