Android编程:如何根据距离传感器数值控制屏幕开关?
嘿,这个需求挺实用的,我之前做过类似功能,给你整理了一套完整的实现方案,一步步来:
1. 声明必要权限
首先在AndroidManifest.xml中添加控制屏幕所需的权限:
<uses-permission android:name="android.permission.WAKE_LOCK" />
注:距离传感器属于普通硬件传感器,不需要额外申请权限。
2. 初始化传感器与屏幕控制组件
先获取传感器管理器实例,再找到距离传感器;同时初始化PowerManager和WakeLock,用于控制屏幕亮灭:
Kotlin 示例代码
private lateinit var sensorManager: SensorManager private var proximitySensor: Sensor? = null private var wakeLock: PowerManager.WakeLock? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 初始化传感器管理器 sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager // 获取距离传感器(TYPE_PROXIMITY) proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) // 初始化PowerManager和WakeLock val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager wakeLock = powerManager.newWakeLock( PowerManager.SCREEN_BRIGHT_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP, "MyApp:ProximityWakeLock" // 自定义标签,用于调试 ) // 检查设备是否支持距离传感器 if (proximitySensor == null) { Toast.makeText(this, "当前设备不支持距离传感器", Toast.LENGTH_SHORT).show() finish() } }
Java 示例代码
private SensorManager sensorManager; private Sensor proximitySensor; private PowerManager.WakeLock wakeLock; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); wakeLock = powerManager.newWakeLock( PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "MyApp:ProximityWakeLock" ); if (proximitySensor == null) { Toast.makeText(this, "当前设备不支持距离传感器", Toast.LENGTH_SHORT).show(); finish(); } }
3. 实现传感器事件监听
创建SensorEventListener,在onSensorChanged方法中根据距离值控制屏幕:
Kotlin 示例代码
private val proximityListener = object : SensorEventListener { override fun onSensorChanged(event: SensorEvent?) { event ?: return // 距离传感器返回的数值,单位通常为厘米 val distance = event.values[0] // 大多数设备中,0.0代表物体贴近传感器 if (distance == 0.0f) { // 贴近时关闭屏幕:释放WakeLock并清除屏幕常亮标志 if (wakeLock?.isHeld == true) { wakeLock?.release() } window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) } else { // 远离时唤醒屏幕:获取WakeLock并添加屏幕常亮标志 if (!wakeLock?.isHeld!!) { wakeLock?.acquire(1000) // 持有1秒足够唤醒屏幕,可按需调整时长 } window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) } } override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { // 传感器精度变化时的处理,一般无需额外操作 } }
Java 示例代码
private SensorEventListener proximityListener = new SensorEventListener() { @Override public void onSensorChanged(SensorEvent event) { float distance = event.values[0]; if (distance == 0.0f) { // 贴近时关闭屏幕 if (wakeLock.isHeld()) { wakeLock.release(); } getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } else { // 远离时唤醒屏幕 if (!wakeLock.isHeld()) { wakeLock.acquire(1000); } getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // 精度变化处理 } };
4. 注册与注销传感器监听
在Activity生命周期中注册和注销监听,避免资源泄漏:
Kotlin 示例代码
override fun onResume() { super.onResume() // 注册传感器监听,SENSOR_DELAY_NORMAL代表正常采样频率 proximitySensor?.let { sensorManager.registerListener(proximityListener, it, SensorManager.SENSOR_DELAY_NORMAL) } } override fun onPause() { super.onPause() // 注销监听,释放WakeLock sensorManager.unregisterListener(proximityListener) if (wakeLock?.isHeld == true) { wakeLock?.release() } } override fun onDestroy() { super.onDestroy() // 最终销毁时确保释放WakeLock wakeLock?.release() }
Java 示例代码
@Override protected void onResume() { super.onResume(); if (proximitySensor != null) { sensorManager.registerListener(proximityListener, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL); } } @Override protected void onPause() { super.onPause(); sensorManager.unregisterListener(proximityListener); if (wakeLock.isHeld()) { wakeLock.release(); } } @Override protected void onDestroy() { super.onDestroy(); if (wakeLock.isHeld()) { wakeLock.release(); } }
5. 关键注意事项
- 设备兼容性:不同厂商的距离传感器返回值范围可能不同,部分设备贴近时返回的是接近0的小数而非严格0.0,建议测试时打印
distance值做适配。 - 电量优化:不要长时间持有WakeLock,按需获取和释放,避免不必要的电量消耗。
- 后台运行:如果需要在后台持续监听传感器,必须使用前台服务,否则系统会限制后台APP的传感器使用权限。
- 权限适配:Android 12及以上版本,
WAKE_LOCK权限无需动态申请,但后台唤醒可能需要额外的权限配置。
内容的提问来源于stack exchange,提问作者Saleh Masoudi
相关产品推荐
相关产品推荐

