START_STICKY在Android KitKat上不起作用
我的一个应用程序有一个后台服务,它使用START_STICKY在Android KitKat上不起作用,android,android-service,sticky,Android,Android Service,Sticky,我的一个应用程序有一个后台服务,它使用START\u STICKY从onStartCommand返回代码,在系统终止时自动重新启动。 这似乎不再适用于Android KitKat。 有什么解决办法吗? 我应该在Kitkat上做些不同的事情来保持服务运行吗 注意:Android开发者组也有类似的讨论,讨论从最近的应用列表中刷取应用。这两个问题是否相关? 编辑:看到Android问题跟踪器上存在开放的bug: Edit2:即使服务在单独的进程中使用startForeground运行,并且在An
START\u STICKY
从onStartCommand
返回代码,在系统终止时自动重新启动。
这似乎不再适用于Android KitKat。
有什么解决办法吗?
我应该在Kitkat上做些不同的事情来保持服务运行吗
注意:Android开发者组也有类似的讨论,讨论从最近的应用列表中刷取应用。这两个问题是否相关?
编辑:看到Android问题跟踪器上存在开放的bug:
Edit2:即使服务在单独的进程中使用startForeground
运行,并且在AndroidManifest.xml文件中使用标记android:stopWithTask=“false”
,也会发生同样的情况
Edit3:Android问题跟踪器上的更多相关bug:
是否有某种解决方法来获得以前的行为?似乎这是Android 4.4中存在的一个bug,通过以下方法解决了它:
@Override
public void onTaskRemoved(Intent rootIntent) {
Intent restartService = new Intent(getApplicationContext(),
this.getClass());
restartService.setPackage(getPackageName());
PendingIntent restartServicePI = PendingIntent.getService(
getApplicationContext(), 1, restartService,
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() +1000, restartServicePI);
}
I/ActivityManager(449): Killing 11073:<your process name>/u0a102 (adj 0): remove task
从中找到此答案此处的问题似乎不会发生在基于AOSP的ROM上。也就是说,我可以很容易地在基于CyanogenMod 11的ROM上重新创建它,但在AOSP ROM(和模拟器)上,START_STICKY的行为完全符合我的预期。这就是说,我看到Nexus5上的人的报告似乎看到了这种行为,所以这可能仍然是AOSP中的一个问题 在模拟器和AOSP ROM上,当我对进程执行“kill 5838”时,我从logcat中看到以下内容(如我所料): 如果通过从“最近的任务”列表中“滑动”结束任务,我会看到相同的重新启动行为。所以这一切都是好的——这意味着核心AOSP代码的行为与以前的级别一样 我正在查看Cyanogenmod服务代码,试图找出为什么事情没有按计划重新启动-还没有运气。看来它应该重新安排时间。Cyanogenmod使用AOSP没有的服务地图-但不清楚这是否是一个问题(可疑) 您可以做的一个相当黑客的解决方法是使用与onTaskRemoved AlarmService类似的机制,在X分钟后启用警报。然后,当你的应用程序启动并运行时,每隔几分钟,你就可以重置警报——因此只有当事情真的被终止而没有重新启动时,警报才会熄灭。这并不是万无一失的——与使用实时的报警服务相比,使用处理程序可以为您提供正常运行时间,因此,即使您的报警设置的时间比“重置”处理程序长,也有可能触发报警。但是如果您设置了一个额外的intent,那么如果您的服务已经启动并运行,您可以选择忽略onstart命令,从而将其变成noop 我一点也不喜欢下面的黑客程序——但它不应该造成任何真正的伤害。如果用户执行显式强制关闭,则报警管理器将销毁所有设置的报警,以便服务不会重新启动(这是用户想要的) 首先,创建一个helper方法,该方法将设置20分钟的警报,从而触发服务的onStartCommand。每2分钟配备一个处理器,该处理器将重置20分钟警报。如果处理器在实时20分钟内运行,警报将永远不会发出。如果设备处于休眠状态(这很好),则不能保证处理程序运行 在onCreate中,可以调用此方法。另外-在onstart命令中,如果您的服务已经启动并正在运行,请确保忽略此选项。例如:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
...
if ((intent != null) && (intent.getBooleanExtra("ALARM_RESTART_SERVICE_DIED", false)))
{
Log.d(TAG, "onStartCommand after ALARM_RESTART_SERVICE_DIED");
if (IS_RUNNING)
{
Log.d(TAG, "Service already running - return immediately...");
ensureServiceStaysRunning();
return START_STICKY;
}
}
// Do your other onStartCommand stuff..
return START_STICKY;
}
这不是一个100%有效的解决方案,但它是迄今为止最好的,因为它几乎完全消除了问题。到目前为止,我集成了此解决方案以及覆盖
onTaskRemoved
(请参阅)和保持活动状态通知(请参阅)。
额外的答案非常感谢强>
经过进一步的调查,这个bug似乎已经存在于Jelly Bean中,并且看起来有一个解决方案(至少在我的案例中是这样的。如果需要,我们将继续测试并更新答案)
据我观察,这种情况只发生在接收由AlarmManager
设置的广播的服务上
要复制错误,请执行以下步骤:
startForeground
)adb shell dumpsys>C:\dumpsys.txt
可以监视不同步骤之间的服务状态。(在dumpsys输出中查找处理LRU列表
)
在步骤2和3中,您将看到如下内容:
Proc # 2: prcp F/S/IF trm: 0 11073:<your process name>/u0a102 (fg-service)
@Override
public void onDestroy() {
Intent intent = new Intent("restartApps");
sendBroadcast(intent);
super.onDestroy();
stopThread();
}
导致这种行为的原因似乎是,接收到的广播将服务从前台状态移出,然后被终止
为了避免这种情况,在为AlarmManager
创建PendingEvent
时,您可以使用此简单解决方案(来源:)
请注意以下步骤:
android.appwidget.action.appwidget\u CONFIGURE
消息并显示新小部件的配置活动时,也会发生同样的情况(将上面的步骤4替换为创建新的widge)
I/ActivityManager(449): Killing 11073:<your process name>/u0a102 (adj 0): remove task
AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent("YOUR_ACTION_NAME");
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, intent, 0);
public class RestartService extends BroadcastReceiver {
private static final String TAG = "RestartService";
public RestartService() {
}
@Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "onReceive");
context.startService(new Intent(context, YourService.class));
}
}
<receiver
android:name=".RestartService"
android:enabled="true" >
<intent-filter>
<action android:name="restartApps" />
</intent-filter>
</receiver>
@Override
public void onDestroy() {
Intent intent = new Intent("restartApps");
sendBroadcast(intent);
super.onDestroy();
stopThread();
}