4、Car App Library入门:Car App Library概述、模板化开发、基础控件使用、生命周期管理
各位同学,今天我们来聊聊Car App Library。说实话,这个库是车载应用开发的基石。我刚开始接触车载开发时,也踩过不少坑,尤其是生命周期管理那块,差点让我加班到怀疑人生。今天我把这些经验都整理出来,希望能帮你少走弯路。
4.1 Car App Library是什么?
Car App Library,简称CAL,是Google为车载系统专门打造的一套UI框架。它跟手机上的Jetpack Compose有点像,但专门针对车载场景做了优化。
为什么要用CAL?你想想看,车载屏幕跟手机屏幕完全不一样。手机你拿在手里,距离眼睛30厘米;车载屏幕呢?至少50厘米开外。而且开车时注意力不能分散,所以UI必须大、清晰、易操作。
CAL的核心特点有三个:
- 模板化开发:提供预设的页面模板,比如列表页、详情页、设置页
- 安全驾驶优先:自动处理驾驶状态下的UI限制
- 统一交互规范:所有应用遵循相同的操作逻辑
重要提示:CAL不是独立的库,它依赖于Android Automotive OS。如果你的项目不是基于AAOS,那CAL可能用不了。
4.2 模板化开发:快速搭建页面
我个人习惯用模板来开发车载应用。为什么?因为省事。CAL提供了几种常用模板,你只需要填充数据就行。
4.2.1 列表模板(ListTemplate)
这是最常用的模板。比如音乐列表、联系人列表、设置项列表,都用它。
// 创建列表模板
ListTemplate.Builder builder = new ListTemplate.Builder();
builder.setTitle("我的音乐");
builder.setHeaderAction(Action.BACK);
// 添加列表项
List<Row> rows = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Row row = new Row.Builder()
.setTitle("歌曲 " + i)
.setSubtitle("艺术家")
.addText("3:45")
.build();
rows.add(row);
}
// 设置列表
CarListAdapter adapter = new CarListAdapter(rows);
builder.setAdapter(adapter);
// 应用到Screen
setTemplate(builder.build());
我在项目中遇到过一个问题:列表项太多时,滑动会卡顿。后来发现是没复用ViewHolder。CAL的CarListAdapter其实已经做了复用,但如果你自定义了布局,记得要手动实现。
4.2.2 网格模板(GridTemplate)
网格模板适合展示图标类内容,比如应用列表、快捷开关。
GridTemplate.Builder builder = new GridTemplate.Builder();
builder.setTitle("应用列表");
// 每个网格项
List<GridItem> items = new ArrayList<>();
for (int i = 0; i < 8; i++) {
GridItem item = new GridItem.Builder()
.setTitle("应用" + i)
.setImage(iconResId)
.setOnClickListener(v -> {
// 处理点击
})
.build();
items.add(item);
}
builder.setItems(items);
setTemplate(builder.build());
小技巧:网格模板的行列数可以自适应。但建议每行不超过4列,否则在车载屏幕上会显得拥挤。
4.2.3 面板模板(PaneTemplate)
面板模板适合详情页。比如歌曲详情、联系人详情。
PaneTemplate.Builder builder = new PaneTemplate.Builder();
builder.setTitle("歌曲详情");
Pane pane = new Pane.Builder()
.setTitle("晴天")
.setSubtitle("周杰伦")
.addText("专辑:叶惠美")
.addText("时长:4:29")
.setImage(albumArt)
.build();
builder.setPane(pane);
setTemplate(builder.build());
4.3 基础控件使用
CAL的控件跟Android原生控件不太一样。它更注重触控和语音交互的兼容性。
| 控件名称 | 用途 | 注意事项 |
|---|---|---|
| Row | 列表中的一行 | 支持标题、副标题、图标、操作按钮 |
| Action | 操作按钮 | 有BACK、APP_ICON、CUSTOM三种类型 |
| CarText | 文本显示 | 自动适配字体大小,支持多行 |
| CarButton | 按钮 | 有PRIMARY、SECONDARY两种样式 |
举个例子,自定义一个带图标的按钮:
Action customAction = new Action.Builder()
.setIcon(R.drawable.ic_settings)
.setOnClickListener(v -> {
// 打开设置
})
.build();
// 添加到模板
builder.setHeaderAction(customAction);
注意:CAL的控件尺寸是固定的,不要尝试用layoutParams去修改。我曾经试过强行改大小,结果在部分车型上显示异常。
4.4 生命周期管理
嗯,这里要注意。车载应用的生命周期跟手机应用有很大区别。手机应用可以自由地在前后台切换,但车载应用不行。
为什么?因为驾驶安全。当车辆行驶时,系统会限制某些操作。比如视频播放、长文本输入,在行驶中会被禁止。
4.4.1 Screen的生命周期
CAL中的Screen类似于Activity,但它有自己的生命周期回调:
public class MyScreen extends Screen {
@Override
public void onStart() {
super.onStart();
// 屏幕可见,开始更新UI
// 比如开始播放动画
}
@Override
public void onResume() {
super.onResume();
// 屏幕获得焦点
// 比如开始语音播报
}
@Override
public void onPause() {
super.onPause();
// 屏幕失去焦点
// 比如暂停语音播报
}
@Override
public void onStop() {
super.onStop();
// 屏幕不可见
// 比如释放资源
}
@Override
public void onDestroy() {
super.onDestroy();
// 屏幕被销毁
// 清理所有资源
}
}
4.4.2 驾驶状态监听
我曾经在项目中遇到一个坑:音乐播放器在行驶中不能显示歌词。后来发现需要监听驾驶状态。
// 获取驾驶状态管理器
CarDrivingStateManager manager = getCarContext()
.getCarService(CarDrivingStateManager.class);
// 注册监听
manager.registerCallback(new CarDrivingStateManager.Callback() {
@Override
public void onDrivingStateChanged(CarDrivingStateEvent event) {
int state = event.getStatus();
if (state == CarDrivingStateEvent.STATUS_DRIVING) {
// 车辆行驶中,隐藏歌词
hideLyrics();
} else {
// 停车状态,显示歌词
showLyrics();
}
}
});
核心要点:生命周期管理的关键在于「状态感知」。你不仅要管理Screen的生命周期,还要感知车辆状态的变化。两者结合,才能做出安全又流畅的车载应用。
4.4.3 资源释放的最佳实践
我建议在onStop()中释放所有非必要的资源。比如网络请求、传感器监听、动画等。为什么?因为车载系统的内存资源很紧张,后台应用随时可能被回收。
@Override
public void onStop() {
super.onStop();
// 取消网络请求
if (call != null && !call.isCanceled()) {
call.cancel();
}
// 停止动画
if (animator != null && animator.isRunning()) {
animator.cancel();
}
// 释放图片缓存
imageLoader.clearCache();
}
说白了,车载开发就是「安全第一」。你写的每一行代码,都要考虑会不会影响驾驶安全。CAL帮我们做了很多限制,但最终的责任还在开发者身上。
好了,这一章的内容就到这里。下一章我们会深入讲解如何用CAL构建一个完整的音乐播放器应用。到时候我会分享更多实战经验,包括如何处理音频焦点、如何管理播放队列等。记得提前预习一下。