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

27,827

Solution 1

To expand on UdeshUk's answer - any use of MediaButtonReceiver (either building pending intents or just receiving media button intents) can result in your service being called with startForegroundService, because MediaButtonReceiver.onReceive starts your service in that way on Oreo. I haven't seen this documented anywhere.

Solution 2

I found the problem. In my notification I have set

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

So when user removes the notification it calls startForegroundService() because I called stopForeground() previously when pausing.

To overcome, I used a custom pending intent and handled it in the onStartCommand() instead of MediaButtonReveiver's PendingIntent

Solution 3

You must call this method inside your Service class onCreate() method:->

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);
        }
    }

Solution 4

Late to the party, but as was mentioned before, it's the MediaButtonReceiver; it has this code:

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

I'm using the receiver in a bound service, so I created a class that has the exact same code as MediaButtonReceiver, except for this line. I replaced it with:

        context.startService(intent);

Solution 5

From the docs 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.

So, you have to call startForeground inside onCreate() for your service.

Share:
27,827

Related videos on Youtube

UdeshUK
Author by

UdeshUK

A research intern at SCoRe Lab and a computer science student at the University of Colombo School of Computing. Interested in ML, Blockchain, mobile, and web development. Loves coffee.

Updated on November 05, 2020

Comments

  • UdeshUK
    UdeshUK over 3 years

    I'm currently working on audio playback app and I'm using a started bound service to play music in background. I start and bind to the service using following code.

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

    It gets promoted to foreground when playing and gets demoted when music is paused.

    // onAudioPlay
    service.startForeground(NOTIFY_ID, notification)
    
    // onAudioPause
    service.stopForeground(false)
    

    Service work fine up to now. But when the notification is swiped(removed) by the user in the paused state, the service crashes after few seconds giving this error.

    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)
    

    This only happens on Oreo and I already read about the background limitations in Oreo. But following points bugs me.

    • This service is a bound service(which aren't affected by limitations)
    • I never use Context.startForegroundService() to start the service.(and don't want to use it)
    • The service doesn't crash when it gets demoted from foreground, it's happens when removing the notification.

    Why is the service is crashing? What am I doing wrong? I'm very thankful if someone tell me whats happening here.

    • Yuchen
      Yuchen over 6 years
      This is interesting. I suggest you post your solution as an answer and mark it as accepted instead of editing the question. It is more clear to the future reader as well.
    • UdeshUK
      UdeshUK over 6 years
      @YuchenZhong Thanks for the suggestion. I added an answer.
  • UdeshUK
    UdeshUK over 6 years
    Yeah. But this happen while my activity is open. So my app isn't in the background. And also I don't start the service with startForegroundService().
  • Steve M
    Steve M about 6 years
    Can you explain how that line of code calls startForegroundService() implicitly? I have similar problem where I never call it and it might provide clues. Thanks.
  • gxcare
    gxcare over 5 years
    I have the same issue calling MediaButtonReceiver.handleIntent, and there is a note in the docs "Once the service is started, it must start to run in the foreground". It was quite cryptic until reading your answer.
  • th3hamm0r
    th3hamm0r over 5 years
    @SteveM the above line creates a PendingIntent which targets the MediaButtonReceiver, which then may call your service with startForegroundService (which also depends on how you configured your intent filters in the manifest). So the best solution to avoid those startForegroundService-calls is to avoid the MediaButtonReveiver, see stackoverflow.com/a/50629196/1394330
  • RJ Aylward
    RJ Aylward almost 5 years
    If you register a MediaButtonReceiver in your manifest Android can try and restart your media session by calling startForegroundService, and if you don't show a notification soon enough in this case it will cause the ANR. You can opt out of this behavior as described in the [docs] (developer.android.com/guide/topics/media-apps/…)
  • Kris B
    Kris B over 4 years
    Do you know if using setMediaButtonReceiver(null) will cause any issues with using external media controls? I updated my code to use this and it still recognizes button commands from my Bluetooth headset but it seems odd to just set it to null.
  • Kris B
    Kris B over 4 years
    Really nice of Google to make us aware of this. What happens if Google ever modifies the code in MediaButtonReceiver? Do you have copy the code into your project everytime there are any changes to it?
  • Kris B
    Kris B over 4 years
    @UdeshUK I'm confused when you said you created a custom pending intent. Wouldn't just adding a notification to onStartCommand() in your MediaBrowserService work?
  • mhashim6
    mhashim6 over 4 years
    I guess so, I guess they did that as some kind of enforcement; you can only access the media button in foreground. That was shortsighted though, the entire services api is a pain any way.
  • Kris B
    Kris B over 4 years
    I just set setMediaButtonReceiver to null and that seemed to work as mentioned here:developer.android.com/guide/topics/media-apps/… I was worried it would effect handling media controls from a Bluetooth headset but it doesn't.
  • UdeshUK
    UdeshUK over 4 years
    @KrisB Sorry I don't use a MediaBrowserService. I have a custom music service to handle playback and handle media files.
  • mhashim6
    mhashim6 over 4 years
    Are you still able to listen to media button's events?
  • Андрей Воробьев
    Андрей Воробьев over 4 years
    @KrisB But it is actual only for Android 5.0 (API level 21) and higher?
  • Андрей Воробьев
    Андрей Воробьев over 4 years
    @RJAylward But it is actual only for Android 5.0 (API level 21) and higher?