先决条件: 作为对我的应用程序的要求的一部分,我需要确保该应用程序在后台运行时不会被Android系统关闭(杀死)。为此,尽管我没有在后台执行任何实际过程,但我只是在维护应用程序状态的情况下实现了Foreground服务。一切正常,除了一件事对我来说不十分清楚如何解决。
问题: 有时(暂时只有一次),我会收到此异常:
android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground():
当我试图停止前台服务而实际上没有启动它时,抛出此异常。
所以,我的问题是-有没有一种方法可以正确地停止前台服务,在实际停止前台服务之前确保它没有运行? 目前,我发现我可以为我的服务使用静态实例,并在停止服务之前将其与null进行比较,或者获取当前正在运行的所有服务的列表。但是所有这些看起来都像是一些“黑客”解决方法。
以下代码: MyForegroundService:
public class ForegroundService extends Service {
public static final int NOTIFICATION_ID = 1;
public static final String CHANNEL_ID = "SessionForegroundServiceChannel";
public static final String ACTION_FOREGROUND_START = "ACTION_FOREGROUND_START";
public static final String ACTION_FOREGROUND_STOP = "ACTION_FOREGROUND_STOP";
public static void startForegroundService(Context context) {
Intent intent = new Intent(context, ForegroundService.class);
intent.setAction(ForegroundService.ACTION_FOREGROUND_START);
ContextCompat.startForegroundService(context, intent);
}
public static void stopForegroundService(Context context) {
Intent intent = new Intent(context, ForegroundService.class);
intent.setAction(ForegroundService.ACTION_FOREGROUND_STOP);
ContextCompat.startForegroundService(context, intent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (ACTION_FOREGROUND_START.equals(intent.getAction())) {
createNotificationChannel();
Intent stopForegroundIntent = new Intent(this, ForegroundServiceBroadcastReceiver.class);
PendingIntent pendingLogoutIntent = PendingIntent.getBroadcast(this,
0, stopForegroundIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
? null
: getString(R.string.app_short_name))
.setContentText(getString(R.string.foreground_description))
.setColor(getResources().getColor(R.color.color))
.setSmallIcon(R.drawable.ic_notification)
.addAction(R.drawable.ic_logout, getString(R.string.logout), pendingLogoutIntent)
.build();
startForeground(NOTIFICATION_ID, notification);
} else if (ACTION_FOREGROUND_STOP.equals(intent.getAction())) {
stopForeground(true);
stopSelf();
}
return START_STICKY;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
getString(R.string.app_name),
NotificationManager.IMPORTANCE_LOW
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
<service
android:name=".ui.ForegroundService"
android:exported="false"
android:stopWithTask="true"/>
我还具有BroadcastReceiver和EventBus来监听一些事件并根据这些事件停止前台。
你们能帮我吗?
答案 0 :(得分:1)
让我在@Pawel评论的内容中添加更多详细信息:
如果没有在调用Context.startForegroundService的三秒钟之内调用Service.startForeground,则会出现此异常。
完整的解决方案如下所示:
对于需要停止前台服务的情况,您需要执行以下操作(伪代码):
if (action == START_FOREGROUND) {
...
startForeground(NOTIFICATION_ID, notification);
} else if (action == STOP_FOREGROUND) {
startForeground(NOTIFICATION_ID, closeNotification); //in case it wasn't started before
stopForeground(true);
stopSelf();
}
即使它并不明显,并且任何文档都没有直接说明,当您需要停止前台时,您需要开始前台,然后再停止(如果有)还没开始)。
感谢@Pawel的提示。