20、传感器测试与调试:传感器模拟器使用、ADB传感器命令、数据可视化工具、性能分析

做传感器开发,最头疼的是什么?

不是写代码,是调试。真机传感器数据飘忽不定,有时候你根本分不清是代码写错了,还是硬件本身就有问题。我早期做计步器算法时,就吃过这个亏——在办公室跑得好好的,一到户外就乱跳,折腾了两天才发现是地磁干扰。

所以这一章,咱们专门聊聊怎么把传感器调试这件事,做得更稳、更快、更准。

20.1 传感器模拟器:没有真机也能跑

你可能会问:没有真机,怎么测传感器?

嗯,Android 模拟器其实自带传感器模拟功能。我个人的习惯是,在写算法初期,先用模拟器把逻辑跑通,再上真机验证。这样能省下不少来回编译的时间。

20.1.1 启用模拟器传感器面板

打开 AVD Manager,启动你的模拟器。然后在模拟器右侧工具栏里,找到三个小点(More Options),点进去选择 Virtual Sensors

你会看到这样一个界面:

┌─────────────────────────────────────┐
│  Virtual Sensors (模拟器传感器面板)   │
├─────────────────────────────────────┤
│  Accelerometer:  x: 0.0  y: 9.8  z: 0.0 │
│  Gyroscope:      x: 0.0  y: 0.0  z: 0.0 │
│  Magnetometer:   x: 0.0  y: 0.0  z: 0.0 │
│  ...                                    │
│  [Presets: 走路 | 跑步 | 旋转 | 自定义] │
└─────────────────────────────────────┘

你可以手动拖动滑块,模拟设备倾斜、旋转。也可以选择预设的「走路」或「跑步」模式,模拟器会自动生成一组连续的传感器数据。

小技巧: 我建议你写一个简单的测试 App,把传感器数据实时打印到 Logcat。然后在模拟器里切换不同预设,观察数据变化是否符合预期。这一步能快速发现算法中的低级错误。

20.1.2 自定义传感器数据文件

预设模式不够用?你可以自己写数据文件。

模拟器支持加载 CSV 格式的传感器数据。格式很简单:

# 时间戳(ms), 加速度X, 加速度Y, 加速度Z
0, 0.0, 9.8, 0.0
16, 0.1, 9.7, 0.2
32, -0.1, 9.9, -0.1
...

在 Virtual Sensors 面板里,点击 Load Data,选择你的 CSV 文件,模拟器就会按时间戳回放数据。我在做跌倒检测算法时,就是用这种方式,把真实采集的跌倒数据喂给模拟器,反复调试阈值参数。

注意: 模拟器的传感器数据是软件模拟的,精度和真实硬件有差距。尤其是陀螺仪和磁力计,模拟器数据往往过于理想。所以,最终验证一定要上真机。

20.2 ADB 传感器命令:命令行里的瑞士军刀

ADB 不只是用来装 App 的。它有一组命令,能直接操作传感器。说白了,你可以用命令行控制传感器开关、查看数据、甚至注入假数据。

20.2.1 查看传感器列表

想知道设备上有哪些传感器?一条命令搞定:

adb shell dumpsys sensorservice

输出会列出所有注册的传感器,包括类型、厂商、分辨率、最大范围等。我曾经用这个命令排查过一个问题:某款平板明明有陀螺仪,但 App 就是检测不到。一查才发现,系统把陀螺仪禁用了。

20.2.2 实时监听传感器数据

想看看传感器当前在输出什么?用这个:

adb shell dumpsys sensorservice --sensor 1

其中 1 是传感器 ID(加速度计通常是 1,陀螺仪是 4)。这条命令会持续输出数据流,直到你按 Ctrl+C。

输出示例:

Sensor: Accelerometer, time=1234567890, x=0.12, y=9.81, z=0.34
Sensor: Accelerometer, time=1234567906, x=0.11, y=9.80, z=0.35
...
实战场景: 我在测试一个手势识别功能时,发现数据偶尔会「卡住」几秒钟。用这条命令实时监听,发现是系统触发了省电策略,把传感器采样率降到了 1Hz。嗯,后来加了 WakeLock 才解决。

20.2.3 注入传感器数据(真机调试利器)

这个功能知道的人不多,但非常实用。你可以用 ADB 向设备注入假数据:

adb shell sensorstest --sensor 1 --value 0.0,9.8,0.0

这条命令会向加速度计注入一组固定值。所有监听该传感器的 App,都会收到这组数据。

有什么用?举个例子:你写了一个计步器,想测试静止状态下会不会误计步。直接注入 0.0, 9.8, 0.0(静止状态),然后看 App 的反应。不用拿着手机傻站着等。

注意: 注入数据需要 root 权限,或者使用 userdebug 版本的固件。普通用户版可能不支持。

20.3 数据可视化工具:让数据「说话」

看 Logcat 里的数字,眼睛会瞎的。我个人的习惯是,把传感器数据实时画成曲线图。一眼就能看出异常。

20.3.1 使用 Android Studio 的 Profiler

Android Studio 自带的 Profiler 其实可以看传感器数据。不过它主要面向 CPU、内存,传感器数据需要额外配置。

你可以在 Profiler 里添加自定义数据点:

// 在代码中插入
Trace.beginSection("sensor_x");
Trace.setCounter("sensor_x", (long)(event.values[0] * 1000));
Trace.endSection();

然后 Profiler 的 Timeline 上就会显示一条实时曲线。虽然精度一般,但胜在方便,不用装额外工具。

20.3.2 第三方工具:Sensor Kinetics

如果你想要更专业的可视化,我推荐 Sensor Kinetics 这个 App。它能把加速度、陀螺仪、磁力计的数据画成三条实时曲线,还支持记录和回放。

界面大概长这样:

┌─────────────────────────────────────┐
│  Sensor Kinetics                     │
├─────────────────────────────────────┤
│  ┌─────────────────────────────────┐ │
│  │ 加速度 X: ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁    │ │
│  │ 加速度 Y: ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁    │ │
│  │ 加速度 Z: ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁    │ │
│  └─────────────────────────────────┘ │
│  [记录] [回放] [导出CSV]              │
└─────────────────────────────────────┘

我在做姿态解算时,经常用这个 App 记录一段真实运动数据,然后导出 CSV,再用 Python 脚本分析。比在手机上调试舒服多了。

20.3.3 自己写一个简单的可视化界面

如果你喜欢折腾,可以自己写一个简单的实时曲线图。用 Canvas 画就行,代码量不大:

public class SensorGraphView extends View {
    private Paint linePaint;
    private Path path;
    private float[] dataBuffer = new float[200];

    @Override
    protected void onDraw(Canvas canvas) {
        // 清空画布
        canvas.drawColor(Color.WHITE);
        // 绘制数据曲线
        path.reset();
        for (int i = 0; i < dataBuffer.length; i++) {
            float x = i * getWidth() / dataBuffer.length;
            float y = getHeight() / 2 - dataBuffer[i] * 10;
            if (i == 0) path.moveTo(x, y);
            else path.lineTo(x, y);
        }
        canvas.drawPath(path, linePaint);
    }

    public void addDataPoint(float value) {
        // 滑动窗口,新数据覆盖旧数据
        System.arraycopy(dataBuffer, 1, dataBuffer, 0, dataBuffer.length - 1);
        dataBuffer[dataBuffer.length - 1] = value;
        postInvalidate();
    }
}

这样,你的 App 里就有一个实时传感器波形图了。调试时看着曲线,比看数字直观得多。

20.4 性能分析:传感器不是免费的

传感器一直在工作,意味着 CPU 一直在处理中断、数据拷贝、回调。如果不注意性能,你的 App 会变成电老虎。

20.4.1 采样率与功耗的平衡

Android 传感器支持不同的采样率:

采样率 延迟(微秒) 典型场景 功耗
SENSOR_DELAY_FASTEST 0 游戏、VR
SENSOR_DELAY_GAME 20,000 手势识别
SENSOR_DELAY_UI 60,000 屏幕旋转
SENSOR_DELAY_NORMAL 200,000 计步器 极低

我见过不少开发者,做计步器也用 FASTEST 模式。结果手机半天就没电了。其实计步器只需要 10-20Hz 的采样率,用 NORMAL 完全够用。

建议: 先确定你的算法需要的最低采样率,然后选择对应的延迟模式。不要无脑用 FASTEST。

20.4.2 使用 Battery Historian 分析功耗

Google 提供了一个叫 Battery Historian 的工具,可以分析 App 的耗电情况。使用方法:

# 1. 重置电池统计信息
adb shell dumpsys batterystats --reset

# 2. 运行你的 App,做各种操作

# 3. 导出电池数据
adb bugreport bugreport.zip

# 4. 上传到 Battery Historian 网页工具

在生成的报告中,你可以看到传感器唤醒 CPU 的频率、每次唤醒的持续时间。如果发现传感器频繁唤醒 CPU,说明你的采样率设置过高,或者没有在不需要时注销监听器。

20.4.3 避免「传感器泄漏」

这是一个很常见的坑。我在项目中遇到过好几次:Activity 销毁了,但传感器监听器没有注销。结果传感器一直在后台工作,手机发烫。

正确的做法:

@Override
protected void onResume() {
    super.onResume();
    sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);
}

@Override
protected void onPause() {
    super.onPause();
    sensorManager.unregisterListener(this);  // 一定要注销!
}

嗯,这里要注意:onPause 里注销,而不是 onDestroy。因为 onPause 一定会被调用,而 onDestroy 不一定。

20.5 本章知识体系

下面这张图,帮你理清传感器测试与调试的完整流程:

传感器测试与调试知识体系 传感器模拟器 AVD 虚拟传感器面板 CSV 数据回放 预设运动模式 无真机也能调试 ADB 传感器命令 dumpsys sensorservice 实时数据监听 注入假数据 命令行瑞士军刀 数据可视化工具 Profiler 自定义曲线 Sensor Kinetics 自绘 Canvas 波形图 让数据「说话」 性能分析 采样率与功耗平衡 Battery Historian 避免传感器泄漏 省电是关键 调试流程总结 模拟器验证逻辑 → ADB 注入测试边界 → 可视化观察波形 → 性能分析优化功耗 常见坑点 1. 模拟器数据太理想,最终必须上真机验证 2. 忘记注销监听器 → 手机发烫 → 用户卸载 App

这张图把四个核心模块串起来了。你从模拟器开始,用 ADB 命令做精细控制,用可视化工具观察数据,最后用性能分析工具确保不耗电。每一步都有对应的工具和方法。

一句话总结: 传感器调试不是玄学,是一套有章可循的工程方法。用好这些工具,你能省下至少一半的调试时间。

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