5、获取Sensor对象:使用getDefaultSensor获取距离传感器
好,咱们继续。上一节我们把SensorManager拿到手了,现在要干正事了——获取距离传感器对象。
说白了,SensorManager就像个传感器仓库管理员。你告诉他“我要距离传感器”,他就给你对应的Sensor对象。如果仓库里没有这个货,他就给你个null。
5.1 标准获取方式
代码其实就一行,但我建议你把它写成一个完整的获取逻辑。我在项目中见过太多人直接拿返回值就用,结果设备不支持时直接崩了。
SensorManager sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
Sensor proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
嗯,这里要注意:getDefaultSensor()返回的是系统推荐的默认距离传感器。大多数手机只有一个距离传感器,所以这个方法够用了。
5.2 处理传感器为null的情况
你想想看,如果设备不支持距离传感器,getDefaultSensor()会返回null。这时候你要是直接调用proximitySensor.getName(),妥妥的NullPointerException。
我曾经在一个平板上遇到过这个问题。那台平板没有距离传感器,但代码里没做判空,结果上线后崩溃率直接飙了。从那以后,我养成了一个习惯:
核心原则:获取传感器后,必须判空。
if (proximitySensor == null) {
// 设备不支持距离传感器
Log.w(TAG, "设备不支持距离传感器");
// 可以提示用户,或者禁用相关功能
return;
}
// 正常使用
Log.i(TAG, "距离传感器: " + proximitySensor.getName());
5.3 获取所有距离传感器
有时候设备可能有多个距离传感器(比如前置和后置)。getDefaultSensor()只返回默认的那个。如果你想拿到所有距离传感器,可以用:
List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_PROXIMITY);
if (sensorList.isEmpty()) {
Log.w(TAG, "没有找到任何距离传感器");
} else {
Log.i(TAG, "找到 " + sensorList.size() + " 个距离传感器");
for (Sensor sensor : sensorList) {
Log.i(TAG, "传感器名称: " + sensor.getName() +
", 供应商: " + sensor.getVendor());
}
}
我个人习惯用getDefaultSensor(),因为大多数场景下只需要一个。但如果你在做多传感器融合或者特殊硬件适配,getSensorList()会更灵活。
5.4 传感器信息一览
拿到Sensor对象后,你可以获取它的详细信息。这些信息在调试和适配时特别有用:
| 方法 | 返回值 | 说明 |
|---|---|---|
| getName() | String | 传感器名称,比如"STK3328 Proximity" |
| getVendor() | String | 供应商,比如"STMicroelectronics" |
| getVersion() | int | 传感器版本号 |
| getMaximumRange() | float | 最大检测距离,单位cm。典型值5.0或8.0 |
| getResolution() | float | 分辨率,即最小变化值 |
| getPower() | float | 功耗,单位mA。距离传感器通常很低,0.5-2mA |
| getMinDelay() | int | 最小采样间隔,单位微秒 |
小技巧:调试时可以把这些信息打印出来,看看不同手机的距离传感器有什么差异。我遇到过一款手机,它的距离传感器最大范围是8.0cm,但实际有效距离只有3cm。这种坑,不打印出来根本发现不了。
5.5 完整代码示例
下面是一个完整的获取距离传感器的工具方法,我直接贴出来:
public class SensorHelper {
private static final String TAG = "SensorHelper";
private SensorManager mSensorManager;
private Sensor mProximitySensor;
public SensorHelper(Context context) {
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
initProximitySensor();
}
private void initProximitySensor() {
if (mSensorManager == null) {
Log.e(TAG, "获取SensorManager失败");
return;
}
mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
if (mProximitySensor == null) {
Log.w(TAG, "设备不支持距离传感器");
// 这里可以回调给UI层,提示用户
return;
}
// 打印传感器信息,方便调试
Log.i(TAG, "距离传感器信息:");
Log.i(TAG, " 名称: " + mProximitySensor.getName());
Log.i(TAG, " 供应商: " + mProximitySensor.getVendor());
Log.i(TAG, " 最大范围: " + mProximitySensor.getMaximumRange() + " cm");
Log.i(TAG, " 分辨率: " + mProximitySensor.getResolution());
Log.i(TAG, " 功耗: " + mProximitySensor.getPower() + " mA");
}
public Sensor getProximitySensor() {
return mProximitySensor;
}
public boolean isProximitySensorAvailable() {
return mProximitySensor != null;
}
}
注意:不要在主线程里做耗时的传感器初始化操作。虽然获取Sensor对象本身很快,但后续注册监听器、处理事件都是在主线程回调的。如果处理不当,容易卡UI。
5.6 知识体系图
我把这一章的核心逻辑画成了流程图,方便你理解:
5.7 常见问题与避坑
- 问题:有些手机的距离传感器在系统设置里可以关闭,这时候
getDefaultSensor()返回什么?
答案:返回的还是Sensor对象,但注册监听器后可能收不到事件。我建议在注册监听器后,先主动获取一次数据,确认传感器是否正常工作。 - 问题:模拟器上能获取到距离传感器吗?
答案:大部分模拟器不支持距离传感器,会返回null。所以测试时尽量用真机。 - 问题:获取传感器需要权限吗?
答案:不需要。获取Sensor对象、注册监听器都不需要额外权限。但如果你要读取其他敏感数据(比如位置),那就另说了。
我的经验:在应用启动时,先检查距离传感器是否可用。如果不可用,直接禁用相关功能,而不是在运行时崩溃。用户体验会好很多。
好了,这一章就到这里。记住:拿到Sensor对象只是第一步,后面还有注册监听器、处理事件、注销监听器等一系列操作。但基础打牢了,后面就顺了。
公众号:蓝海资料掘金营,微信deep3321