外观
任务迁移、配置、虚拟屏与输入
1. Activity 跨屏为什么可能重建?怎样保持页面状态?
**标准回答:**跨屏会改变与窗口相关的 Configuration,例如可用尺寸、密度、方向和资源选择条件。是否重建取决于具体变化、应用声明及系统策略。声明 configChanges 可以自行处理相应变化,但应用必须更新资源和布局;没有重建,也仍可能重新 measure、layout 和 draw。
页面状态应按生命周期分层:ViewModel 保存同一作用域内跨配置重建的状态,SavedStateHandle 或实例状态保存适量可恢复信息,业务数据进入持久层。原进程死亡后,原 ViewModel 不会继续存在。
**追问:为了动画平滑,能不能把所有重建都跳过?**不应把跳过重建当成通用优化。它可能留下错误资源、尺寸和密度。可以由替身图层承担过渡,同时让真实应用完成必要配置更新;对系统定制字段必须说明分支与验证范围。
2. 如何在指定 Display 启动页面?为什么有时启动后仍回主屏?
**标准回答:**公开应用可通过 ActivityOptions.setLaunchDisplayId 表达目标显示意图,但最终放置还受显示可访问性、权限、Activity 和任务复用规则等影响。它不是一个能任意操控所有应用任务的许可。复用已有任务、显示已断开、目标显示不允许启动等,都要结合系统决策分析。
我会在请求、任务决策、ActivityRecord、窗口创建和实际显示等阶段分别记录 displayId,检查任务是否真的进入目标显示。不同显示应使用正确的 display / window Context 和当前窗口度量,避免从默认屏的缓存宽高构建目标界面。
**追问:NEW_TASK 能保证跨屏成功吗?**不能。它参与任务选择,不能代替显示访问检查,也不等于创建新进程。要一起检查 flags、launchMode、taskAffinity、调用方和已有任务。
3. VirtualDisplay、录屏和 Launcher 有什么关系?
**标准回答:**VirtualDisplay 是一个逻辑显示,其渲染输出写入提供的 Surface。录屏是一类利用显示内容捕获和编码输出的应用场景,但不是 VirtualDisplay 的唯一用途。它能承载什么窗口、是否有系统装饰、能否启动 Home,受创建方式、标志、权限和系统策略影响。
一个虚拟屏不会因为被创建就自动拥有 Launcher。检查屏幕空白时,应分别确认输出 Surface 有没有消费者、显示是否允许承载 Activity、任务是否启动成功、窗口是否有有效 buffer。对于 MediaProjection 等公共能力,还需遵循对应用户授权和版本要求。
**追问:释放 VirtualDisplay 后为什么还有画面或资源?**生产者、消费者、缓冲区、编码器和显示对象具有各自生命周期。停止业务后,应按拥有者收尾相关对象,不要认为一次 release 能替你释放所有外部资源。
4. 副屏返回键、输入焦点和 Resumed 状态如何排查?
**标准回答:**先确认输入来自哪个设备、携带哪个 displayId、分发给哪个窗口,再检查该显示的任务和返回行为。可见、Resumed、获得输入焦点和 top-resumed 是相关但不同的状态;多窗口或多显示下,不能用“全系统只有一个 Resumed Activity”的旧模型解释所有问题。
Android 支持特定配置下的每显示焦点,但是否启用、非显示专属输入如何路由、输入法在哪个显示出现,都要看系统配置和策略。副屏按返回跳到主屏时,要区分事件路由错误与应用自己的导航错误;盲目启动 MAIN / HOME 可能掩盖焦点问题。
**追问:两个页面都 Resumed,能同时独占摄像头吗?**不能。生命周期状态并不保证独占资源,应用还要处理资源优先级变化、断开回调与恢复。跨屏动画期间也不应提前让被遮盖或失效窗口继续消费输入。