作者:神之骰时间:2025-01-22 00:33:07
课上讲到 The Activity Lifecycle,返回键演示的时候翻了车。
不是应该是 onPause() -> onStop() -> onDestroy()
么,
怎么onPause() -> onStop() -> onSaveInstanceState()
啦
哦,原来在 Android 12 ( SDK 31) 之后引入了新的 feature:OnBackPressed()
操作在某些场景下会表现出类似于按下 Home 键的效果——也就是不会销毁当前 Activity,而是将整个任务移动到后台-- MoveToBack()
,从而保留当前 Activity 的实例状态。很多同学会注意到,如果当前 Activity 是任务栈 Task 的根 Activity -- isTaskRoot()
,则系统默认执行的行为不再是调用 finish()
,而是像 Home 键一样退到桌面。
下面从系统机制和源码原理的角度,梳理一下它是如何判断并实现的。
在 Android 较早的版本中,默认情况下按下返回键会调用 Activity.onBackPressed()
,最终通常会导致当前 Activity 被 finish()
掉。如果当前 Activity 恰好是根 Activity(即任务栈中唯一的或者最底部的那个),则按下返回键后,整个 App 就退出前台,表面上看起来与按下 Home 键的效果类似,但在绝大部分机型上,会直接销毁当前的根 Activity。
然而,有时开发者并不希望根 Activity 被销毁、或者希望把 App 移到后台。我们可以在 onBackPressed()
中自己去调用:
moveTaskToBack(true);
从而将任务栈移到后台,保留实例状态。这样做的效果就类似于按下 Home 键。
从 Android 12(API 31)开始,系统在导航手势和传统返回键的处理上进行了一些调整,引入了对“根 Activity 直接退到桌面”(而非销毁)的默认支持。也就是说,如果当前 Activity 是整个任务栈的根部,系统会直接将任务移动到后台,而不会再去销毁根 Activity。这带来了更一致的用户体验:在“全屏手势导航”场景下,用户从屏幕边缘向内滑动做“返回”时,如果栈里只剩根 Activity,系统就会把它当作返回桌面来处理。
需要注意的是,这个默认行为也和各厂商定制系统有一定关系,有些系统在更早版本也会出现根 Activity “退到后台而非 finish” 的情形;但从 AOSP 的角度,Android 12 开始是一个更统一、更明确的行为。
isTaskRoot()
在应用层,如果你想判断当前 Activity 是否为任务栈的根 Activity,可以直接调用:
javaCopyboolean isRoot = isTaskRoot();
这个方法是由 Activity
提供,用来判断“当前 Activity 是否就是栈底的那一个”。它内部会去与系统的 ActivityManager / ActivityTaskManager 进行通信,判断自己在当前任务栈中的位置。
ActivityRecord
/ Task
检查在系统的 ActivityManagerService(或更具体的 ActivityTaskManagerService)内部,每个正在运行的 Activity 都会对应一个 ActivityRecord
。同样,每个任务栈(Task)也会有对应的数据结构来维护所有该 Task 内的 ActivityRecord 列表。
当用户触发“返回”操作时,系统会层层调用到 ActivityTaskManagerService
或 ActivityRecord
的相关调度逻辑,流程大致如下:
WindowManagerService
分发按键/手势事件,然后回调到 PhoneWindow
/ Activity
等应用层或系统层的相应接口。ActivityStack
或者 Task
中寻找当前焦点 Activity 的 ActivityRecord
,检查它是否是当前任务栈的根记录(isRootOfTask
)。在 Android 12 之前,系统默认行为是直接调用 finish(),进而导致 App 在前台退出(实际上就只剩下 Launcher 等,表面看和回到桌面类似)。在 Android 12 中,官方逐步切换为默认 moveTaskToBack,由此也就产生了“像 Home 键”的效果——根 Activity 不会被 destroy,而是“保存”当前实例并转到后台。
moveTaskToBack(true)
Activity
类中公开的方法,内部会调用到 ActivityManager
或 ActivityTaskManager
,将当前任务栈放到后台。类似按下 Home 键
moveTaskToBack
非常相似。onBackPressed()
中手动调用 moveTaskToBack(true)
或重写相关的返回逻辑。从 Android 12 开始,这个逻辑会默认执行。某些手机如果没按 AOSP 完全实现,也可能会有差异,需要具体机型测试。onBackPressed()
中做更精细的控制。isTaskRoot()
和系统底层判断也依然是生效的,但注意应用逻辑不要与系统行为冲突。isTaskRoot()
判断),那么在用户执行返回操作时,默认会执行 “moveTaskToBack()
” 把任务移至后台,而不会再直接 finish()
根 Activity。ActivityTaskManager
/ ActivityRecord
判断当前 Activity 是否在任务栈底,然后在分发返回事件时做出不同处理。如果是根节点,则调用 moveTaskToBack(true)
,效果等同于按 Home 键。onBackPressed()
中自行处理;否则在新系统上默认就能实现“根 Activity 返回即最小化”的体验。简单来说,这项改动让系统在根 Activity 时与“返回桌面”的行为更加直观统一,提升了用户的手势导航和应用导航体验。从实现角度,系统还是依赖 ActivityRecord
、isTaskRoot()
等底层判断,一旦确认当前 Activity 是栈底,便不会调用 finish(),而是将整个任务移动到后台,从而保留 Activity 的实例状态。
---
别急 Android 13 以后,onBackPressed()
直接 @deprecated, 又引入了更多的 feature
。。。to be continued