如何修复使用加速度计的应用在锁屏模式下停止运行的问题?
解决Android锁屏后应用停止运行的问题
嘿,这个问题我之前开发传感器应用时也踩过坑!Android系统在锁屏或者屏幕自动熄灭后,会把后台应用的CPU资源大幅限制,甚至暂停传感器监听和MediaPlayer播放,所以你的应用就直接停了。下面给你两个靠谱的解决方案,结合你的代码来改:
方案一:使用前台服务(最推荐)
前台服务的优先级远高于普通后台服务,系统不会轻易杀死它,而且能持续保持传感器监听和MediaPlayer运行。不过Android 8.0+要求前台服务必须显示一条通知,让用户知道应用在后台运行。
步骤1:创建前台服务类
把你的传感器监听、外力计算和MediaPlayer逻辑移到Service里,这样即使Activity进入后台,服务依然能运行:
public class AccelerometerService extends Service implements SensorEventListener { private SensorManager sensorManager; private Sensor accelerometerSensor; private MediaPlayer mediaPlayer; private float maxf; @Override public void onCreate() { super.onCreate(); // 初始化传感器 sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); // 初始化MediaPlayer(替换成你的MP3文件) mediaPlayer = MediaPlayer.create(this, R.raw.your_mp3_resource); // 创建前台通知(Android 8.0+必须创建通知渠道) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( "accelerometer_channel", "外力检测服务", NotificationManager.IMPORTANCE_LOW ); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } Notification notification = new NotificationCompat.Builder(this, "accelerometer_channel") .setContentTitle("外力检测运行中") .setContentText("正在监听加速度传感器") .setSmallIcon(R.drawable.ic_notification) // 替换成你的通知图标 .build(); // 启动前台服务 startForeground(1, notification); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 注册传感器监听 sensorManager.registerListener(this, accelerometerSensor, SensorManager.SENSOR_DELAY_NORMAL); return START_STICKY; // 服务被系统杀死后尝试自动重启 } @Override public void onSensorChanged(SensorEvent event) { // 这里写你的外力计算逻辑(和你之前Activity里的逻辑一致) float x = event.values[0]; float y = event.values[1]; float z = event.values[2]; float force = (float) Math.sqrt(x*x + y*y + z*z); if (force > maxf) { maxf = force; // 触发MP3播放 if (mediaPlayer != null && !mediaPlayer.isPlaying()) { mediaPlayer.start(); } } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) {} @Override public void onDestroy() { super.onDestroy(); // 释放所有资源,避免内存泄漏 if (sensorManager != null) { sensorManager.unregisterListener(this); } if (mediaPlayer != null) { mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; } stopForeground(true); // 移除前台通知 } @Nullable @Override public IBinder onBind(Intent intent) { return null; // 如果不需要Activity绑定服务,返回null即可 } }
步骤2:在Activity中启动服务
修改你的Activity代码,启动刚才创建的前台服务:
private TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.your_textview_id); // 启动前台服务 Intent serviceIntent = new Intent(this, AccelerometerService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(serviceIntent); // Android 8.0+用这个方法 } else { startService(serviceIntent); // 低版本用这个 } } // 可选:当Activity退出时停止服务 @Override protected void onDestroy() { super.onDestroy(); Intent serviceIntent = new Intent(this, AccelerometerService.class); stopService(serviceIntent); }
步骤3:配置Manifest文件
在AndroidManifest.xml中添加权限和服务声明:
<!-- 前台服务权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- 如果需要保持CPU唤醒,可选添加 --> <uses-permission android:name="android.permission.WAKE_LOCK" /> <application ...> <!-- 注册服务 --> <service android:name=".AccelerometerService" /> </application>
方案二:使用唤醒锁(不推荐,仅作补充)
唤醒锁可以让CPU保持唤醒状态,但在Android 6.0+的Doze模式下可能失效,而且会增加耗电,所以不如前台服务可靠。如果一定要用,可以这样做:
private SensorManager sensorManager; private Sensor accelerometerSensor; private MediaPlayer mediaPlayer; private PowerManager.WakeLock wakeLock; private float maxf; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.your_textview_id); // 初始化唤醒锁 PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); wakeLock = powerManager.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, "MyApp::AccelerometerWakeLock" ); // 初始化传感器和MediaPlayer sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mediaPlayer = MediaPlayer.create(this, R.raw.your_mp3_resource); } @Override protected void onResume() { super.onResume(); wakeLock.acquire(); // 获取唤醒锁 sensorManager.registerListener(this, accelerometerSensor, SensorManager.SENSOR_DELAY_NORMAL); } // 注意:锁屏时Activity会进入onPause,这里不要释放唤醒锁和传感器,否则还是会停 // @Override // protected void onPause() { // super.onPause(); // wakeLock.release(); // sensorManager.unregisterListener(this); // } @Override protected void onDestroy() { super.onDestroy(); wakeLock.release(); // 必须释放唤醒锁,否则会一直耗电 sensorManager.unregisterListener(this); mediaPlayer.release(); } // 你的传感器监听逻辑... @Override public void onSensorChanged(SensorEvent event) { // 和之前的计算逻辑一致 } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) {}
关键提醒
- 优先选择前台服务,它能绕过系统的后台限制,稳定性更高
- 前台服务的通知不能省略,要写清楚应用在做什么,避免用户困惑
- 记得在不需要服务时及时停止,减少不必要的耗电和内存占用
内容的提问来源于stack exchange,提问作者Kỳ Đoàn Văn
相关产品推荐
相关产品推荐

