第4章:Car App 开发基础
车载应用开发,和手机开发完全是两码事。我刚开始接触 Android Automotive 时,心想不就是个 Android 吗?结果第一个 Demo 跑起来就翻车了——界面被拉伸得不成样子,触摸事件也乱套。嗯,这里面的门道,咱们得好好捋一捋。
4.1 车载应用的生命周期
车载应用的生命周期,说白了就是「车机版 Activity 的一生」。但和手机不同的是,车机上的 Activity 会受到更多系统级事件的干扰。
核心差异点:
- 手机:用户主动切换 App
- 车机:系统强制接管(来电、导航、语音)
我习惯把车载 Activity 的生命周期分为三个阶段:
- 前台阶段:onCreate → onStart → onResume。和手机一样,但要注意 onResume 可能被频繁触发。
- 可见但非交互阶段:onPause。车机里这个状态很常见,比如导航弹窗覆盖了你的 App。
- 后台阶段:onStop → onDestroy。系统可能随时杀掉你的进程来释放内存。
避坑指南:我曾经在 onPause 里保存用户输入的数据,结果发现某些车机在低内存时根本不走 onPause,直接杀进程。后来我改用 onSaveInstanceState 配合 Room 数据库,才彻底解决。
4.2 多窗口与分屏适配
车机屏幕越来越大,分屏成了标配。你的 App 必须能在 1/3 屏幕、1/2 屏幕甚至画中画模式下正常工作。
为什么会这样?因为车机系统会强制分屏——左边导航,右边音乐,上面还有状态栏。你的 App 可能被塞进任何一个角落。
4.2.1 尺寸适配策略
| 屏幕占比 | 典型场景 | 适配要点 |
|---|---|---|
| 100% | 全屏媒体播放 | 使用 ConstraintLayout 自适应 |
| 50% | 分屏音乐+导航 | 隐藏次要信息,保留核心操作 |
| 30% | 画中画视频 | 只显示播放控件,文字尽量少 |
注意:不要使用固定 dp 值。我见过一个 App 在 10 寸屏上完美运行,换到 12.3 寸屏上按钮直接飞出屏幕。用 match_parent 和 wrap_content 才是正道。
4.2.2 代码示例:分屏适配
// 在 AndroidManifest.xml 中声明
<activity
android:name=".MainActivity"
android:resizeableActivity="true"
android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout" />
// 监听分屏状态变化
override fun onMultiWindowModeChanged(isInMultiWindowMode: Boolean) {
super.onMultiWindowModeChanged(isInMultiWindowMode)
if (isInMultiWindowMode) {
// 切换到精简布局
showCompactLayout()
} else {
// 恢复全屏布局
showFullLayout()
}
}
我个人习惯在 onMultiWindowModeChanged 里做布局切换,而不是在 onCreate 里判断。因为用户可能在行驶中动态调整分屏比例。
4.3 车载 UI 设计规范
车机 UI 和手机 UI 最大的区别是什么?是「安全第一」。你想想看,司机在开车时,视线离开前方的时间不能超过 2 秒。所以我们的 UI 设计必须遵循「一眼看懂,一触即达」的原则。
4.3.1 核心设计原则
- 大触控区域:按钮至少 48dp × 48dp,推荐 64dp。手指在颠簸的车里很难精准点击。
- 高对比度:文字和背景的对比度不低于 4.5:1。阳光直射时,低对比度根本看不清。
- 减少层级:最多两级导航。不要让司机在菜单里翻来翻去。
- 语音优先:所有操作都要有语音替代方案。
我记得有一次测试,一个 App 的「设置」按钮只有 32dp,测试司机在高速上点了三次都没点中。后来我们改成了 64dp,问题立刻解决。别小看这 16dp 的差距。
4.3.2 车载 UI 组件规范
| 组件 | 最小尺寸 | 间距要求 | 说明 |
|---|---|---|---|
| 按钮 | 48dp × 48dp | ≥ 8dp | 圆角矩形,避免尖锐边角 |
| 列表项 | 高度 ≥ 56dp | ≥ 12dp | 支持滑动操作 |
| 文本 | 最小 14sp | 行高 1.5 倍 | 推荐使用系统字体 |
| 图标 | 24dp × 24dp | ≥ 16dp | 配合文字标签 |
4.4 安全驾驶模式
安全驾驶模式,说白了就是「开车时别让司机分心」。Android Automotive 提供了两种机制:
- 驾驶模式检测:通过车辆 CAN 总线获取车速,判断车辆是否在行驶中。
- 内容限制:行驶中禁止显示视频、长文本、复杂表单。
4.4.1 驾驶模式检测实现
// 获取驾驶状态管理器
val car = Car.createCar(context)
val drivingStateManager = car.getCarManager(Car.DRIVING_STATE_SERVICE)
// 监听驾驶状态变化
drivingStateManager?.registerListener(object : DrivingState.OnDrivingStateChangedListener {
override fun onDrivingStateChanged(state: DrivingState) {
when (state.status) {
DrivingState.DRIVING_STATUS_UNRESTRICTED -> {
// 停车状态,显示全部内容
showAllContent()
}
DrivingState.DRIVING_STATUS_NO_VIDEO -> {
// 行驶中,隐藏视频
hideVideoContent()
}
DrivingState.DRIVING_STATUS_NO_KEYBOARD -> {
// 行驶中,禁用键盘输入
disableKeyboardInput()
}
}
}
})
我曾经踩过一个坑:驾驶状态检测在模拟器上永远返回「停车状态」。后来才发现,模拟器没有 CAN 总线数据,必须用真实车机或模拟器插件才能测试。所以,别在模拟器上验证驾驶模式逻辑。
4.4.2 内容限制策略
根据 Google 的规范,行驶中应该:
- ✅ 显示导航信息
- ✅ 显示音乐播放控件
- ✅ 显示来电信息
- ❌ 显示视频/动画
- ❌ 显示长文本列表
- ❌ 显示设置菜单
- ❌ 显示键盘输入框
小技巧:我习惯在 ViewModel 里维护一个 isDriving 状态,所有 UI 组件都观察这个状态。这样切换逻辑集中在一处,不会出现某个界面忘记限制的情况。
4.5 本章知识体系
下面这张图总结了本章的核心知识点,你可以把它当作开发时的检查清单:
这四个模块是车载应用开发的基石。你想想看,如果生命周期没处理好,App 可能被系统杀掉;分屏没适配好,界面可能变形;UI 设计不规范,司机可能分心;驾驶模式没实现,可能违反法规。每一个环节都不能掉链子。
总结一下:车载应用开发,本质上是在「功能完整」和「驾驶安全」之间找平衡。我做了这么多项目,最大的体会就是——宁可少一个功能,也不能让司机多看一眼屏幕。