使用 finishAffinity() 和 moveTaskToBack() 的区别是什么?各自适用于什么场景?

解读

国内面试官问这道题,核心想确认两点:

  1. 你是否真的“杀”掉过 Activity,还是只是“退到后台”;
  2. 面对国产 ROM 激进的后台管控与微信、支付宝这类超级 App的“留活”需求,你能否选对 API。
    答成“都能退出”直接挂;答成“finishAffinity 会杀进程”也挂;必须精确到 Task、Activity 记录、生命周期、国产系统差异四个维度。

知识点

  1. Task 与 Affinity:
    • Task 是用户感知的“最近任务”里的卡片;Affinity 是 AndroidManifest 中 taskAffinity 字段,决定 Activity 归属哪个 Task。
  2. finishAffinity():
    • 只作用于当前 Task;
    • 把当前 Activity 及其之上、同属一个 Affinity 的所有 Activity 一次性出栈并走完整 onDestroy();
    • 不会杀进程,也不会影响其他 Affinity 的 Task;
    • 国产 ROM 的“最近任务”里,对应卡片如果只剩被 finishAffinity 的 Task,卡片会消失,但进程仍在缓存。
  3. moveTaskToBack(true):
    • 把当前 Activity 所在的整个 Task(不论多少 Activity)直接压到后台,生命周期只走到 onStop(),不会 onDestroy();
    • 最近任务卡片保留,用户可一键切回;
    • 返回 true/false 可判断是否成功,国产 ROM 若授予“后台弹出界面”权限失败,会返回 false。
  4. 国内特殊坑:
    • 小米/华为“后台常驻”开关、OPPO 的“冷冻”策略,会让 moveTaskToBack 后 5 min 进程被强制清理;
    • 微信“假退出”方案用 moveTaskToBack + 前台 Service + 推送保活,finishAffinity 会被系统视为“用户主动关闭”,反而更容易被回收。

答案

finishAffinity() 会把当前 Task 中、与调用 Activity 具有相同 taskAffinity 的所有 Activity 一次性销毁,生命周期完整执行到 onDestroy(),Task 在最近任务中消失,但进程仍在缓存;适用于“退出登录后清空本账号所有界面”或支付类 App 结束收银台流程,确保用户下次从 Launcher 启动时走进全新栈。
moveTaskToBack(true) 则是把整个 Task 整体压入后台,Activity 不销毁,仅到 onStop(),最近任务卡片保留;适用于 IM、地图、音频等需要“像退出实则保活”的场景,配合前台 Service 实现国产 ROM 下的保活策略。
一句话:真正想“杀界面”用 finishAffinity,想“假退出、真保活”用 moveTaskToBack;在国内 ROM 上,后者必须再申请“后台弹出界面”与“自启动”权限,否则仍可能被系统回收。

拓展思考

  1. Android 12 的“后台启动限制”与 13 的“Task 快照”机制,让 moveTaskToBack 后如果没有任何前台 Service,5 秒内 Task 快照变灰,用户点击卡片会重新走冷启动;保活方案必须升级到 expedited WorkManageruser-initiated data transfer 白名单。
  2. 折叠屏大屏场景下,系统会为同一 Affinity 的 Activity 创建双 Task(主屏与副屏),finishAffinity 只会销毁当前屏幕所属 Task,另一侧 Task 仍存活;若需彻底退出,需遍历 ActivityManager.AppTask 逐个 finish。
  3. 银行类 App 为了过银联检测,要求“退出即清栈”,但监管又要求“退出不杀进程”以便推送风控消息;业内通用做法是:首页按返回时先 moveTaskToBack 给用户“秒退”感知,5 秒无再次切回事件后,发送延迟广播再 finishAffinity,兼顾体验与合规。