28、后台监听:如何在Service中持续获取加速度数据?
前面几章我们都在Activity里玩传感器,一退出页面数据就断了。但很多场景下——比如计步、跌倒检测、车辆碰撞预警——你需要App在后台甚至锁屏时也能持续监听加速度。这时候就得请出Service了。
说白了,Service就是Android里专门干「后台活」的组件。它没有界面,但能一直跑。我最早做运动监测App时,就踩过Service被系统杀掉的坑,后来才慢慢摸清门道。
为什么不能在Activity里一直监听?
你想想看,用户按了Home键,Activity就进入onStop状态。系统随时可能回收它。就算不回收,传感器回调也会跟着暂停。所以我们需要一个「打不死的小强」——Service。
但注意,Service也不是绝对安全的。Android 8.0以后对后台限制越来越严。嗯,这里要分情况讨论。
方案一:前台Service(推荐)
这是目前最稳妥的方式。前台Service会显示一个持续通知,告诉用户「我在后台干活」。系统不会轻易杀它。
我个人习惯用前台Service做传感器监听,因为:
- 优先级高,系统几乎不会回收
- 用户能感知到App在运行,合规
- 适合长时间监听(比如计步器)
核心思路:在Service的onCreate里注册传感器,在onDestroy里注销。前台Service通过startForeground()启动。
public class SensorService extends Service implements SensorEventListener {
private SensorManager sensorManager;
private Sensor accelerometer;
private static final int NOTIFICATION_ID = 1001;
@Override
public void onCreate() {
super.onCreate();
// 初始化传感器
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 启动前台Service
startForeground(NOTIFICATION_ID, buildNotification());
// 注册监听器
if (accelerometer != null) {
sensorManager.registerListener(this, accelerometer,
SensorManager.SENSOR_DELAY_NORMAL);
}
// 如果Service被杀死,自动重启
return START_STICKY;
}
@Override
public void onSensorChanged(SensorEvent event) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
// 这里处理数据,比如写入文件或发送广播
Log.d("SensorService", "X: " + x + ", Y: " + y + ", Z: " + z);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// 精度变化时处理
}
@Override
public void onDestroy() {
super.onDestroy();
// 一定要注销监听,否则传感器一直开着耗电
sensorManager.unregisterListener(this);
}
private Notification buildNotification() {
// Android 8.0+ 需要通知渠道
NotificationChannel channel = new NotificationChannel(
"sensor_channel",
"传感器服务",
NotificationManager.IMPORTANCE_LOW
);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.createNotificationChannel(channel);
return new Notification.Builder(this, "sensor_channel")
.setContentTitle("加速度传感器")
.setContentText("正在后台监听中...")
.setSmallIcon(android.R.drawable.ic_dialog_info)
.build();
}
}
小技巧:START_STICKY能让Service被系统杀掉后自动重启。但别太依赖它,Android 12以后这个行为也变了。
方案二:普通后台Service(不推荐)
如果你不需要长时间运行,只是短暂采集几秒钟数据,普通Service也行。但要注意:
- Android 8.0以上,后台Service在几分钟内就会被系统停止
- 锁屏后可能直接被杀
- 适合「一次性采集」场景
我曾经在做一个跌倒检测Demo时,用了普通Service。结果手机放口袋里锁屏后,Service就挂了。后来改成前台Service才稳定。
生命周期管理:别让传感器一直开着
这是很多新手容易忽略的点。传感器一旦注册,就会持续消耗电量。哪怕你Service在跑,如果不需要数据了,一定要注销监听。
我建议在以下时机注销:
- Service的onDestroy()里——必须做
- 用户主动停止监听时——比如点击「停止」按钮
- 长时间没有数据变化时——可以加个超时逻辑
避坑指南:我曾经有个项目,Service里注册了传感器但忘记注销。结果用户反馈手机发烫、掉电快。查了半天发现是Service被销毁时没走onDestroy()——因为系统直接杀了进程。后来我在onTaskRemoved()和onLowMemory()里也加了注销逻辑。
数据传递:Service怎么把数据给Activity?
Service采集到数据,总得让UI层知道吧?常用的方式有:
- 广播(Broadcast):简单直接,适合低频数据
- 回调接口:通过Binder绑定Service,但要注意内存泄漏
- LiveData/Flow:配合ViewModel,生命周期安全
- 文件/数据库:适合大量数据,比如记录一整天的加速度
我个人偏爱LiveData方案。在Service里持有一个LiveData对象,Activity观察它。这样即使Activity重建,数据也不会丢。
// 在Service中
public class SensorService extends Service {
private MutableLiveData<float[]> sensorData = new MutableLiveData<>();
public LiveData<float[]> getSensorData() {
return sensorData;
}
@Override
public void onSensorChanged(SensorEvent event) {
float[] values = event.values.clone();
sensorData.postValue(values); // 注意用postValue,因为是在子线程
}
}
// 在Activity中
SensorService service = ...;
service.getSensorData().observe(this, values -> {
// 更新UI
textView.setText("X: " + values[0]);
});
SVG流程图:Service中传感器监听的生命周期
电量优化:别让传感器成为电老虎
加速度传感器本身功耗不高,但如果一直以最高频率采样,电量还是会哗哗地掉。我建议:
- 降低采样频率:SENSOR_DELAY_NORMAL就够了,别用FASTEST
- 批量处理:攒一批数据再写入,别来一次写一次
- 条件触发:比如只有加速度超过阈值时才高频采样
- 结合Doze模式:Android 6.0以后的省电模式会限制传感器
我的经验:做计步器时,我用了SENSOR_DELAY_UI(约60ms一次),然后每10次回调才计算一次步数。这样既省电,精度也够。
兼容性:不同厂商的坑
嗯,这里要特别提一下。华为、小米、OPPO等厂商对后台限制比原生Android更严格。有些手机甚至不允许前台Service长时间运行传感器。
我曾经在小米手机上测试,前台Service跑了10分钟就被系统弹窗提示「该应用正在耗电」。用户点一下「停止」就全完了。
解决方案?没有完美的。只能:
- 引导用户加入电池优化白名单
- 使用JobScheduler定期唤醒采集
- 或者干脆用厂商提供的运动健康API
总结
在Service中持续获取加速度数据,核心就三件事:
- 用前台Service保活
- 生命周期里正确注册/注销传感器
- 用合适的方式把数据传给UI层
记住,传感器监听是一把双刃剑。用好了能做出很酷的功能,用不好就是电老虎。多测试不同机型,尤其是国产ROM,你会发现很多意想不到的「惊喜」。
公众号:蓝海资料掘金营,微信deep3321