前提条件: 作为我的应用程序的要求之一,我需要确保该应用程序在后台时不会被Android系统关闭(终止)。为此,我实现了前台服务(Foreground service),即使我不在后台执行任何实际进程,只是维护应用程序的状态。除一个问题外,一切都运行得很好,这个问题我不太清楚如何解决。
问题: 有时候(目前只出现一次),我收到这个异常:
android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground():
当我试图停止前台服务,但实际上它并没有启动时,会抛出此异常。
因此,我的问题是 - 有没有一种正确的方式来停止前台服务,在实际停止之前确保它没有在运行? 目前我发现可以为我的服务创建静态实例,并在停止服务之前将其与 null 进行比较,或获取当前运行的所有服务列表。但所有这些都像是一些“hack”解决方法。
以下是一些代码: 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 来监听一些事件并根据这些事件停止前台服务。
你们能帮忙吗?
ContextCompat.startForegroundService(Context, Intent)
,则您的服务必须在3秒内响应startForeground(Int, Notification)
,即使您的意图是停止服务处于前台。 - Pawelif (ACTION_FOREGROUND_START.equals(intent.getAction())) { startForeground(NOTIFICATION_ID, notification); } else if (ACTION_FOREGROUND_STOP.equals(intent.getAction())) { stopForeground(true); stopSelf(); }
如果按照您建议的做法,我将会陷入无限循环之中。我不需要另一个通知来停止前台。我还有什么遗漏吗? - idk.the.nameContext.startForegroundService
后的3秒内没有调用Service.startForeground
,则会出现此异常。就是这样。 - PawelService.startForeground
。为此,有stopForeground(boolean)
方法。只有在服务未启动时才需要调用Service.startForeground
。但问题是,如何确保服务已经启动。 - idk.the.namestopForeground
和stopSelf()
函数的原因是什么?您可以尝试删除stopSelf
。 - keshav kowshik