绑定服务崩溃并出现 "Context.startForegroundService() did not then call Service.startForeground()" 错误

Bound service crash with "Context.startForegroundService() did not then call Service.startForeground()" error

我目前正在开发音频播放应用程序,我正在使用已启动的绑定服务在后台播放音乐。我使用以下代码启动并绑定到服务。

val intent = Intent(context, MusicService::class.java)
context.startService(intent)
context.bindService(intent, serviceConnection, 0)

播放时提升到前台,暂停时降级。

// onAudioPlay
service.startForeground(NOTIFY_ID, notification)

// onAudioPause
service.stopForeground(false)

目前服务工作正常。但是当用户在暂停状态下滑动(删除)通知时,服务会在几秒钟后崩溃并给出此错误。

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.myplayer, PID: 4380
    android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
        android.app.ActivityThread$H.handleMessage(ActivityThread.java:1775)
        android.os.Handler.dispatchMessage(Handler.java:105)
        android.os.Looper.loop(Looper.java:164)
        android.app.ActivityThread.main(ActivityThread.java:6541)
        java.lang.reflect.Method.invoke(Native Method)
      com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

这只发生在 Oreo 上,我已经了解了 Oreo 的背景限制。但是以下几点让我很烦恼。

为什么服务崩溃了?我究竟做错了什么?如果有人告诉我这里发生了什么,我将非常感激。

来自文档 8.0 Behavior Changes

The system allows apps to call Context.startForegroundService() even while the app is in the background. However, the app must call that service's startForeground() method within five seconds after the service is created.

因此,您必须在 onCreate() 中调用 startForeground 来为您的服务提供服务。

我发现了问题。在我的通知中我设置了

setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(service, PlaybackStateCompat.ACTION_STOP))

因此,当用户删除通知时,它会调用 startForegroundService(),因为我之前在暂停时调用了 stopForeground()。

为了解决这个问题,我使用了一个自定义的待定意图并在 onStartCommand() 中处理它,而不是 MediaButtonReveiver 的 PendingIntent

您必须在服务中调用此方法 class onCreate() 方法:->

private void startServiceOreoCondition(){
        if (Build.VERSION.SDK_INT >= 26) {


            String CHANNEL_ID = "my_service";
            String CHANNEL_NAME = "My Background Service";

            NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                    CHANNEL_NAME,NotificationManager.IMPORTANCE_NONE);
            ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);

            Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                    .setCategory(Notification.CATEGORY_SERVICE).setSmallIcon(R.drawable.ic_tgc_icon).setPriority(PRIORITY_MIN).build();

            startForeground(101, notification);
        }
    }

扩展 - MediaButtonReceiver 的任何使用(构建待定意图或仅接收媒体按钮意图)都可能导致使用 startForegroundService 调用您的服务,因为 MediaButtonReceiver.onReceive 以这种方式在 Oreo 上启动您的服务。我没有在任何地方看到这个记录。

派对迟到了,但如前所述,是 MediaButtonReceiver;它有这个代码:

    @Override
    public void onReceive(Context context, Intent intent) {
        ...
        startForegroundService(context, intent);
        ...
    }

我在绑定服务中使用接收器,所以我创建了一个 class,它的代码与 MediaButtonReceiver 完全相同,除了这一行。我将其替换为:

        context.startService(intent);

我有同样的问题,但我使用通知服务修复了它

public void createNotificationChannel(){
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

        NotificationChannel serviceChanel =new NotificationChannel(
                CHANNEL_ID,
                "Forground service Chane"
                , NotificationManager.IMPORTANCE_DEFAULT
        );
        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(serviceChanel);
    }
}

在 class

的开头创建香奈儿 ID

public static final String CHANNEL_ID = "ForegroundServiceChannel";

和服务 onStartCommand 内部

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {


        createNotificationChannel();
        Intent notificationIntent = new Intent(this , MainActivity.class);
        PendingIntent pendingIntent =PendingIntent.getActivity(this,0,notificationIntent,0);
        Notification notification = new NotificationCompat.Builder(this,CHANNEL_ID)
                .setContentTitle("ForgroundService")
                .setContentText("Any message")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(pendingIntent)
                .build();
        startForeground(1,notification);
    }

输入代码

来源https://androidwave.com/foreground-service-android-example/

MediaButtonReceiver 调用 startForegroundService ,它是我的罪魁祸首。当我没有媒体可播放(播放列表为空)时,我的问题就出现了。我通过在 onStartCommand:

中显示通知并立即取消它来解决这个问题
    if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);

        builder.setSmallIcon(R.drawable.notification)
                .setContentTitle("")
                .setContentText("")
                .setSmallIcon(R.drawable.notification);
        startForeground(99, builder.build());
        stopForeground(true);
        
        MyMediaButtonReceiver.handleIntent(mediaSessionCompat, intent);
    
        return START_NOT_STICKY;
      }