Android 8.1.0后台服务自动停止问题求助(附相关代码)
排查Android 8.1.0后台服务自动停止及活动更新被移除的问题
根据你提供的代码和日志信息,核心问题出在Android 8.0+的后台服务限制政策,加上代码里的几个小疏漏,导致服务启动后很快被系统销毁,进而触发了onDestroy()里的removeActivityUpdatesButtonHandler(),所以你看到了Removed activity updates successfully!的日志。下面一步步分析原因并给出修复方案:
核心原因:Android 8.0+后台服务限制
从Android 8.0(API 26)开始,系统严格限制后台应用创建后台服务:
- 如果应用处于后台状态(没有可见Activity),调用
startService()启动的服务会在几秒内被系统强制停止。 - 必须使用
startForegroundService()替代startService(),并且在服务启动后5秒内调用startForeground()显示一个前台通知,否则系统会直接终止服务并抛出ForegroundServiceStartNotAllowedException。
你的代码里用的是startService(),完全符合这个被系统终止的场景,这是服务自动停止的主要原因。
次要问题:WakeLock使用不当
你的WakeLock是onCreate()里的局部变量,方法执行完毕后这个变量会被GC回收,导致唤醒锁可能被系统提前释放,起不到保持服务唤醒的作用;而且没有在onDestroy()里释放,还可能造成内存泄漏。
修复方案
1. 改用前台服务启动方式
修改MainClass里的startTracking()方法,根据系统版本选择启动方式:
private void startTracking() { if (!isMyServiceRunning()) { Intent intent = new Intent(MainActivity.this, BackgroundDetectedActivitiesService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // Android 8.0+必须用前台服务启动 startForegroundService(intent); } else { startService(intent); } } }
2. 在服务中实现前台通知逻辑
修改BackgroundDetectedActivitiesService,添加前台通知代码,并修复WakeLock的使用:
public class BackgroundDetectedActivitiesService extends Service { private static final String TAG = BackgroundDetectedActivitiesService.class.getSimpleName(); private Intent mIntentService; private PendingIntent mPendingIntent; private ActivityRecognitionClient mActivityRecognitionClient; private PowerManager.WakeLock wakeLock; // 改为成员变量 IBinder mBinder = new BackgroundDetectedActivitiesService.LocalBinder(); // ... 其他原有代码保持不变 @Override public void onCreate() { super.onCreate(); // 修复WakeLock:保存为成员变量,添加超时时间 PowerManager mgr = (PowerManager) getSystemService(Context.POWER_SERVICE); wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock:BackgroundTracking"); wakeLock.acquire(10 * 60 * 1000L); // 10分钟超时,避免长期持有 // 创建前台通知(Android 8.0+必须) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( "tracking_channel", "Activity Tracking", NotificationManager.IMPORTANCE_LOW // 低优先级,避免打扰用户 ); NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel); } Notification notification = new NotificationCompat.Builder(this, "tracking_channel") .setContentTitle("Activity Tracking") .setContentText("Running in background") .setSmallIcon(R.mipmap.ic_launcher) // 必须设置小图标 .build(); // 启动前台服务,通知ID要唯一 startForeground(1, notification); // 原有初始化代码 mActivityRecognitionClient = new ActivityRecognitionClient(this); mIntentService = new Intent(this, DetectedActivitiesIntentService.class); // 适配Android 8.0+的PendingIntent Flag int pendingIntentFlag = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_UPDATE_CURRENT; mPendingIntent = PendingIntent.getService(this, 1, mIntentService, pendingIntentFlag); requestActivityUpdatesButtonHandler(); } // ... 其他原有代码保持不变 @Override public void onDestroy() { super.onDestroy(); // 释放WakeLock if (wakeLock != null && wakeLock.isHeld()) { wakeLock.release(); } removeActivityUpdatesButtonHandler(); } }
3. 额外优化建议
- 关闭电池优化:引导用户在系统设置中关闭你的应用的电池优化(路径:设置 > 电池 > 电池优化 > 找到你的应用 > 选择“不优化”),避免系统在后台杀死服务。
- 检查权限:虽然Android 8.1不需要动态申请
ACTIVITY_RECOGNITION权限,但要确保Manifest里的权限声明正确,并且应用已经被授予该权限。 - 避免长期持有WakeLock:WakeLock会增加耗电,尽量只在必要时持有,或者设置合理的超时时间。
验证修复
修改后重新测试:
- 启动应用,调用
startTracking()。 - 查看日志,应该会看到
Successfully requested activity updates,而不会很快出现Removed activity updates successfully!。 - 切换到后台,服务应该会保持运行,前台通知栏会显示你设置的通知。
内容的提问来源于stack exchange,提问作者Dim




