4. 注册与注销监听:registerListener与unregisterListener的正确使用时机

好,咱们接着聊。上一节我们把 SensorManager 和 Sensor 对象都拿到手了,接下来就是最关键的一步——让传感器真正工作起来。

说白了,registerListener 就是告诉系统:「嘿,我要开始监听这个传感器了」。而 unregisterListener 则是:「好了,我不听了,你歇着吧」。听起来简单?嗯,但我在项目里见过太多人在这两个 API 上翻车。

4.1 registerListener 的三种重载

先看看官方给我们提供了哪几种注册方式。我个人习惯把它们分成三类:

方法签名 采样率参数 适用场景
registerListener(SensorEventListener, Sensor, int) 延迟级别(SENSOR_DELAY_*) 大多数普通场景
registerListener(SensorEventListener, Sensor, int, Handler) 延迟级别 + 指定 Handler 需要在特定线程处理回调
registerListener(SensorEventListener, Sensor, int, int) 延迟级别 + 最大报告延迟(微秒) 需要批量处理传感器事件

你可能会问:「延迟级别到底选哪个?」我直接给你一个经验值:

  • SENSOR_DELAY_NORMAL(200,000 微秒):屏幕方向、环境光这类变化不频繁的场景。省电。
  • SENSOR_DELAY_UI(60,000 微秒):UI 交互需要,比如根据倾斜角度做动画。我在做体感游戏时常用这个。
  • SENSOR_DELAY_GAME(20,000 微秒):游戏、实时姿态检测。耗电明显增加。
  • SENSOR_DELAY_FASTEST(0 微秒):能多快就多快。除非你真的需要毫秒级响应,否则别碰它。我曾经在一个项目里用了 FASTEST,结果手机发烫到能煎鸡蛋。

核心原则:采样率够用就行,别贪快。霍尔传感器通常用 NORMAL 或 UI 就足够了。

4.2 在 Activity 生命周期中管理传感器

这是本章的重头戏。很多新手会把 registerListener 写在 onCreate 里,然后忘了注销。结果呢?Activity 销毁了,传感器还在后台跑,电量哗哗地掉。

正确的做法是:在 onResume 中注册,在 onPause 中注销

为什么是 onPause 而不是 onDestroy?因为 onPause 一定会被调用,而 onDestroy 不一定。比如用户按了 Home 键,Activity 只是暂停,但传感器应该停止监听——你想想看,用户都切出去了,你还开着传感器干嘛?

public class HallSensorActivity extends AppCompatActivity {

    private SensorManager sensorManager;
    private Sensor hallSensor;
    private SensorEventListener hallListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hall);

        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        hallSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

        // 初始化监听器
        hallListener = new SensorEventListener() {
            @Override
            public void onSensorChanged(SensorEvent event) {
                // 处理霍尔数据
                float x = event.values[0];
                // 更新UI或其他逻辑
            }

            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {
                // 精度变化时处理
            }
        };
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (hallSensor != null) {
            sensorManager.registerListener(hallListener, hallSensor,
                    SensorManager.SENSOR_DELAY_NORMAL);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(hallListener);
    }
}

我的习惯:在 onPause 里注销后,我会把监听器置为 null 吗?不会。因为 onResume 里还要用。但如果你在 onDestroy 里也做一次 unregisterListener,也没坏处——系统会忽略重复注销。

4.3 注销的坑:我曾经踩过的

讲个真实案例。有一次我做智能保护壳项目,霍尔传感器用来检测翻盖状态。我在 onStop 里注销了监听器,结果发现每次从后台切回来,传感器要等好几秒才有反应。

排查了半天,原因是什么?onStop 和 onPause 的调用时机不同。onPause 之后 Activity 可能还可见(比如对话框弹出),但 onStop 之后 Activity 就完全不可见了。如果你在 onStop 才注销,那用户切到另一个 App 再回来,中间这段时间传感器其实还在跑。

所以记住:注销要早,注册要晚。onPause 注销,onResume 注册,这是黄金法则。

特别注意:如果你在多个地方注册了同一个监听器,系统会保留最后一次注册的配置。注销时只需要调用一次 unregisterListener,系统会帮你清理所有关联。

4.4 知识体系:生命周期与传感器管理

下面这张图是我自己整理的,把 Activity 生命周期和传感器注册注销的对应关系画清楚了。你一看就明白。

Activity生命周期与传感器管理 onCreate onStart onResume onPause onStop 初始化 SensorManager registerListener unregisterListener 只初始化,不注册 ✅ 正确时机:开始监听 ✅ 正确时机:停止监听

4.5 多传感器场景下的管理

如果你的 Activity 需要同时监听多个传感器(比如霍尔 + 加速度计),我建议你用一个统一的监听器对象,在 onSensorChanged 里通过 sensor.getType() 区分。

private SensorEventListener multiListener = new SensorEventListener() {
    @Override
    public void onSensorChanged(SensorEvent event) {
        switch (event.sensor.getType()) {
            case Sensor.TYPE_MAGNETIC_FIELD:
                // 处理霍尔数据
                break;
            case Sensor.TYPE_ACCELEROMETER:
                // 处理加速度数据
                break;
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // 统一处理精度变化
    }
};

这样做的好处是:注销时只需要一行代码。你想想看,如果每个传感器都单独搞一个监听器,那注销的时候得写好几行,还容易漏掉。

最佳实践总结:

  • onResume 注册,onPause 注销——雷打不动
  • 一个监听器处理多个传感器——简洁高效
  • 采样率选 NORMAL 或 UI——省电够用
  • 注销前检查 sensorManager 是否为 null——防止空指针

好了,这一节的内容就这些。记住:注册和注销不是小事,它直接关系到你的 App 耗电和稳定性。我在代码审查时,第一眼就看生命周期里有没有正确处理传感器。这个习惯,建议你也养成。

公众号:蓝海资料掘金营,微信 deep3321