26、结合Notification:当磁场强度超过阈值时发送通知提醒

好,咱们继续往下走。

前面几章我们一直在讲怎么读霍尔传感器的数据,怎么算磁场强度。但说实话,光在Logcat里看数字,那只是给自己看的。真正做产品,你得让用户知道——比如手机壳合上了、磁吸支架吸住了、或者某个磁场异常了。

这时候就需要通知(Notification)登场了。

我个人习惯把这种场景叫做「阈值触发+用户提醒」。说白了就是:后台一直盯着磁场数据,一旦超过你设定的门槛,就弹个通知出来。嗯,这里要注意,不是每次超过都弹,得加防抖逻辑,不然用户手机会被通知刷爆。

26.1 核心思路:监听 + 判断 + 通知

整个流程其实就三步:

  1. 监听霍尔传感器,拿到实时磁场值
  2. 判断是否超过阈值,并且满足防抖条件
  3. 发送系统通知,提醒用户

我在项目中遇到过一种情况:测试时发现通知总是重复弹出。后来排查发现,是因为传感器更新频率太高,每次变化都触发了判断。所以后来我加了个「上次通知时间」的标记,至少间隔3秒才允许再次弹通知。

关键点:通知的触发条件一定要加防抖。否则用户会骂你。

26.2 代码实现:从传感器到通知的完整链路

下面这段代码,我直接贴一个完整的Service实现。你可以在后台跑这个Service,它负责监听霍尔传感器,并在磁场强度超过阈值时弹出通知。

public class HallSensorService extends Service implements SensorEventListener {

    private SensorManager sensorManager;
    private Sensor hallSensor;
    private static final float THRESHOLD = 50.0f; // 阈值,单位微特斯拉
    private long lastNotifyTime = 0;
    private static final long NOTIFY_INTERVAL = 3000; // 防抖间隔3秒

    @Override
    public void onCreate() {
        super.onCreate();
        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        if (sensorManager != null) {
            hallSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (hallSensor != null) {
            sensorManager.registerListener(this, hallSensor, SensorManager.SENSOR_DELAY_NORMAL);
        }
        return START_STICKY;
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            float x = event.values[0];
            float y = event.values[1];
            float z = event.values[2];
            float magnitude = (float) Math.sqrt(x * x + y * y + z * z);

            // 判断是否超过阈值
            if (magnitude > THRESHOLD) {
                long now = System.currentTimeMillis();
                if (now - lastNotifyTime > NOTIFY_INTERVAL) {
                    lastNotifyTime = now;
                    sendNotification("磁场强度超标", "当前值:" + String.format("%.1f", magnitude) + " μT");
                }
            }
        }
    }

    private void sendNotification(String title, String content) {
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    "hall_sensor_channel",
                    "霍尔传感器提醒",
                    NotificationManager.IMPORTANCE_HIGH
            );
            manager.createNotificationChannel(channel);
        }

        Notification notification = new NotificationCompat.Builder(this, "hall_sensor_channel")
                .setSmallIcon(android.R.drawable.ic_dialog_alert)
                .setContentTitle(title)
                .setContentText(content)
                .setAutoCancel(true)
                .setPriority(NotificationCompat.PRIORITY_HIGH)
                .build();

        manager.notify(1001, notification);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) { }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (sensorManager != null) {
            sensorManager.unregisterListener(this);
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

小提示:别忘了在AndroidManifest.xml里声明Service,并且如果是Android 8.0以上,启动Service要用startForegroundService(),否则会被系统杀掉。

26.3 阈值怎么定?

你可能会问:阈值设多少合适?

嗯,这个问题其实没有标准答案。我做过几个项目,总结了一些经验值:

场景 建议阈值(μT) 说明
普通环境磁场 30 ~ 60 日常环境,比如靠近音箱、显示器
磁吸支架/磁吸配件 100 ~ 200 磁铁靠近时,磁场会明显升高
强磁铁靠近 300 以上 比如钕磁铁,或者磁吸充电座

我个人习惯是先跑一遍日志,看看正常环境下的磁场基线是多少。比如你办公室可能平均40μT,那阈值设在80μT就比较合理。别拍脑袋定个1000,那可能永远触发不了。

26.4 避坑指南:我曾经踩过的坑

这里分享几个我实际遇到过的问题:

  • 通知不显示? 检查一下通知渠道(NotificationChannel)是否创建了。Android 8.0以后,没有渠道的通知是发不出来的。
  • 通知重复弹出? 就是前面说的防抖问题。加个时间戳判断,别每次传感器变化都弹。
  • Service被系统杀掉? 尤其是国产手机,后台限制很严。建议用前台Service,或者绑定一个通知栏常驻通知。
  • 传感器数据跳变? 霍尔传感器偶尔会有毛刺。我一般会加一个简单的滑动平均滤波,取最近3~5个值的平均再做判断。

注意:不要在主线程里做耗时操作。onSensorChanged是跑在传感器线程的,但通知发送本身很快,所以没问题。如果你要写文件或者网络请求,记得切线程。

26.5 知识体系梳理

下面这张图,我把本章的核心逻辑画出来了。你看一眼就明白整个流程了。

霍尔传感器阈值通知流程 霍尔传感器监听 onSensorChanged 阈值判断 magnitude > THRESHOLD 防抖检查 时间间隔 > 3秒 防抖未通过,忽略 发送通知 NotificationManager 记录上次通知时间 lastNotifyTime = now 核心逻辑:监听 → 判断 → 防抖 → 通知 → 更新计时 防抖机制防止通知频繁弹出,提升用户体验

你看,整个流程其实不复杂。关键就两个地方:阈值设得合理,防抖做得到位。这两点做好了,通知功能基本就稳了。

扩展思路:你还可以把通知改成震动、响铃,或者结合前台Service做一个常驻通知栏显示实时磁场值。这些我在后面的章节会提到,但你现在就可以自己试试。


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