9、车载设置与车辆信息:CarPropertyManager读取车速/油量/空调、CarSensorManager、车辆设置面板开发
各位同学,今天我们来聊一个很实在的话题——车载应用怎么跟车辆本身“对话”。说白了,就是你的App怎么知道车现在跑多快、油箱还剩多少油、空调设了多少度。这些数据,在Android Automotive里主要通过CarPropertyManager和CarSensorManager来获取。
我在做第一个车载项目时,踩过一个坑:以为车速数据随时都能读到,结果发现有些属性需要特定权限,有些数据在车辆熄火后就拿不到了。嗯,今天咱们就把这些门道讲清楚。
9.1 CarPropertyManager:车辆属性的“万能钥匙”
CarPropertyManager是Android Automotive里最核心的车辆数据接口。它管理着车辆的各种属性——车速、油量、空调温度、车门状态等等。你可以把它理解成一个“属性仓库”,每个属性都有一个唯一的ID。
核心概念:每个车辆属性都有一个PropertyId,通过这个ID来读写数据。属性可以是整数、浮点数、字符串,甚至是复杂的对象。
9.1.1 获取CarPropertyManager实例
第一步,先拿到Car对象,然后获取管理器。代码很简单:
// 获取Car实例
Car car = Car.createCar(context);
// 获取CarPropertyManager
CarPropertyManager propertyManager =
(CarPropertyManager) car.getCarManager(Car.PROPERTY_SERVICE);
// 别忘了在不用的时候释放
car.disconnect();
我个人习惯在onCreate里初始化,在onDestroy里释放。你想想看,如果忘记释放,会导致内存泄漏,这在车载系统上可是大忌。
9.1.2 读取车速
车速是最常用的车辆数据之一。它的PropertyId是VehiclePropertyIds.PERF_VEHICLE_SPEED。读取方式如下:
// 读取当前车速(单位:千米/小时)
float speed = propertyManager.getProperty(
Float.class,
VehiclePropertyIds.PERF_VEHICLE_SPEED,
0 // areaId,一般传0
);
// 注册监听,实时获取车速变化
propertyManager.registerCallback(callback,
VehiclePropertyIds.PERF_VEHICLE_SPEED,
0);
小提示:车速数据是浮点数,单位是km/h。有些车型会返回m/s,记得做单位转换。我在项目中遇到过一台测试车,返回的速度值比实际快了一倍,后来发现是单位配置问题。
9.1.3 读取油量
油量信息稍微复杂一点。它有两个相关属性:FUEL_LEVEL(当前油量)和FUEL_LEVEL_LOW(低油量警告)。
// 读取当前油量(单位:升)
float fuelLevel = propertyManager.getProperty(
Float.class,
VehiclePropertyIds.FUEL_LEVEL,
0
);
// 检查是否低油量
boolean isLowFuel = propertyManager.getProperty(
Boolean.class,
VehiclePropertyIds.FUEL_LEVEL_LOW,
0
);
// 显示到UI上
textView.setText("剩余油量: " + fuelLevel + " L");
我曾经在测试时发现,有些车在油箱加满后,FUEL_LEVEL返回的值会超过标称容量。嗯,这其实是传感器的误差范围,建议你在UI上做个上限截断。
9.1.4 读取空调状态
空调控制涉及多个属性:目标温度、风量、模式等。这里以读取空调开关状态和目标温度为例:
// 读取空调开关状态
boolean acOn = propertyManager.getProperty(
Boolean.class,
VehiclePropertyIds.HVAC_AC_ON,
VehicleArea.ZONE_ROW_1 // 第一排座位区域
);
// 读取目标温度(单位:摄氏度)
float targetTemp = propertyManager.getProperty(
Float.class,
VehiclePropertyIds.HVAC_TEMPERATURE_SET,
VehicleArea.ZONE_ROW_1
);
// 设置空调温度
propertyManager.setProperty(
Float.class,
VehiclePropertyIds.HVAC_TEMPERATURE_SET,
VehicleArea.ZONE_ROW_1,
24.5f // 设置到24.5度
);
注意:空调属性通常需要CONTROL_CAR_CLIMATE权限。没有权限的话,setProperty会抛出SecurityException。记得在AndroidManifest里声明权限。
9.2 CarSensorManager:传感器数据的“专属通道”
有些车辆数据不适合通过CarPropertyManager来获取,比如轮速传感器、加速度传感器等。这时候就要用CarSensorManager了。
说白了,CarSensorManager专门处理那些高频、实时的传感器数据。它的数据更新频率可以很高,适合做驾驶辅助类的功能。
9.2.1 获取CarSensorManager
CarSensorManager sensorManager =
(CarSensorManager) car.getCarManager(Car.SENSOR_SERVICE);
9.2.2 读取传感器数据
以读取轮速传感器为例:
// 注册传感器监听
sensorManager.registerListener(
new CarSensorEventCallback() {
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensorType ==
CarSensorManager.SENSOR_TYPE_WHEEL_SPEED) {
float[] values = event.floatValues;
// values[0] 左前轮速
// values[1] 右前轮速
// values[2] 左后轮速
// values[3] 右后轮速
updateWheelSpeedUI(values);
}
}
},
CarSensorManager.SENSOR_TYPE_WHEEL_SPEED,
CarSensorManager.SENSOR_RATE_NORMAL // 更新频率
);
经验之谈:传感器数据的更新频率有几种选择:SENSOR_RATE_FASTEST(最快)、SENSOR_RATE_NORMAL(正常)、SENSOR_RATE_UI(适合UI更新)。我建议UI展示用SENSOR_RATE_UI,否则更新太快反而导致界面卡顿。
9.3 车辆设置面板开发实战
好了,理论知识讲完了。咱们来做一个实际的车辆设置面板。这个面板包含车速显示、油量显示、空调控制三个模块。
9.3.1 整体架构
先画一张架构图,看看各个模块怎么配合:
9.3.2 核心代码实现
下面是一个简化版的车辆设置面板实现。我把它分成了三个模块:
public class VehicleSettingsFragment extends Fragment {
private CarPropertyManager propertyManager;
private CarSensorManager sensorManager;
// UI组件
private TextView speedText;
private TextView fuelText;
private TextView tempText;
private SeekBar tempSeekBar;
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(
R.layout.fragment_vehicle_settings,
container, false);
initUI(view);
initCarServices();
return view;
}
private void initUI(View view) {
speedText = view.findViewById(R.id.speed_text);
fuelText = view.findViewById(R.id.fuel_text);
tempText = view.findViewById(R.id.temp_text);
tempSeekBar = view.findViewById(R.id.temp_seekbar);
// 空调温度调节
tempSeekBar.setOnSeekBarChangeListener(
new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(
SeekBar seekBar,
int progress,
boolean fromUser) {
if (fromUser) {
// 将进度转换为温度值(16-30度)
float temp = 16 + (progress / 100f) * 14;
setAcTemperature(temp);
}
}
});
}
private void initCarServices() {
Car car = Car.createCar(getContext());
propertyManager = (CarPropertyManager)
car.getCarManager(Car.PROPERTY_SERVICE);
sensorManager = (CarSensorManager)
car.getCarManager(Car.SENSOR_SERVICE);
// 注册数据更新回调
registerPropertyCallbacks();
}
private void registerPropertyCallbacks() {
// 车速回调
propertyManager.registerCallback(
new CarPropertyManager.CarPropertyEventCallback() {
@Override
public void onChangeEvent(
CarPropertyValue value) {
float speed = (float) value.getValue();
getActivity().runOnUiThread(() ->
speedText.setText(
String.format("%.1f km/h", speed)));
}
@Override
public void onErrorEvent(
int propertyId, int zone) {
// 处理错误
}
},
VehiclePropertyIds.PERF_VEHICLE_SPEED,
0);
// 油量回调
propertyManager.registerCallback(
new CarPropertyManager.CarPropertyEventCallback() {
@Override
public void onChangeEvent(
CarPropertyValue value) {
float fuel = (float) value.getValue();
getActivity().runOnUiThread(() ->
fuelText.setText(
String.format("%.1f L", fuel)));
}
},
VehiclePropertyIds.FUEL_LEVEL,
0);
}
private void setAcTemperature(float temp) {
try {
propertyManager.setProperty(
Float.class,
VehiclePropertyIds.HVAC_TEMPERATURE_SET,
VehicleArea.ZONE_ROW_1,
temp);
tempText.setText(
String.format("%.1f°C", temp));
} catch (SecurityException e) {
// 权限不足时的处理
Toast.makeText(getContext(),
"没有空调控制权限",
Toast.LENGTH_SHORT).show();
}
}
}
9.3.3 权限声明
别忘了在AndroidManifest里声明需要的权限:
<uses-permission
android:name="android.car.permission.CAR_SPEED" />
<uses-permission
android:name="android.car.permission.CAR_ENERGY" />
<uses-permission
android:name="android.car.permission.CONTROL_CAR_CLIMATE" />
<uses-permission
android:name="android.car.permission.CAR_SENSOR" />
避坑指南:我曾经在项目里漏掉了CAR_SENSOR权限,结果传感器回调一直不触发。调试了半天才发现是权限问题。记住,每个数据源都要检查对应的权限。
9.4 常见问题与最佳实践
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 数据更新不及时 | 回调注册频率太低 | 使用SENSOR_RATE_FASTEST或缩短轮询间隔 |
| 权限异常 | 缺少对应权限声明 | 检查AndroidManifest和运行时权限 |
| UI卡顿 | 数据更新频率过高 | 使用SENSOR_RATE_UI或做数据降频 |
| 车辆熄火后数据异常 | 车辆进入低功耗模式 | 监听车辆状态,熄火后停止数据请求 |
嗯,最后说一句:车载开发跟手机开发最大的不同,就是数据源的不确定性。你永远不知道下一台测试车会给你返回什么奇怪的数据。所以,做好数据校验和异常处理,比什么都重要。
今天的分享就到这里。记住,多测试几台车,多踩几个坑,经验就积累起来了。
公众号:蓝海资料掘金营,微信deep3321