先决条件。作为应用需求的一部分,我需要确保应用在后台不会被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来监听一些事件,并根据这些事件停止前台。
你们能帮帮我吗?
让我对@Pawel评论的内容补充更多细节。
如果你没有在调用Context.startForegroundService后3秒内调用Service.startForegroundService,你就会得到这个异常,这就是全部的内容。
下面是完整的解决方案的样子。
当你需要停止前台服务时,你需要做以下工作(伪代码):
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的提示。