问题
Spotify and Google Music allows a user to play music in background allowing also the media notification to be dismissible. When you move one of these apps to background, then pause the playback, you are able to dismiss the media notification. However if you don't dismiss the notification, so it is left in paused state for long time, the System won't kill the "audio service" as the notification is always visible and immediately react to play/pause.
As far as I know it is not possible using foreground services as in order to dismiss the notification, we'd need to call stopForeground(false), which would let system to kill the service.
Here is how we do it right now, in our app:
When playback is started, we run MusicService as a foreground service with following code:
startForeground(mediaNotification)
Then, when user leave the app, he is able to control the playback via media notification. As the notification is tightly coupled with the MusicService, user won't be able to dismiss it until we call:
stopForeground(false)
That's why we call this method when user press pause button. However this makes a Service background, so system will kill it in short period of time.
How Spotify and Google Music could workaround it? What is the way to achieve it?
回答1:
I think you can have a timer in your service that restarts your service after a while if the user stopped the music your timer will keep it from dying and if the user clicked play button do as what you already do before.
回答2:
Using a combination of Pouya's answer and some independent research, I have a code snippet that behaves fairly close to apps like Spotify using the OOTB MediaPlayer. There is probably a more elegant solution, but this is the quick and dirty version - I have too much code scattered about to post, so have an overview instead:
When the mediaplayer is paused, I run two pieces of code. First, after updating the notification bar I demote it from a foreground service to a background one with:
public void demoteNotifyBar() {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
stopForeground(STOP_FOREGROUND_DETACH);
else
stopForeground(false);
}
and then I start a new timer, that remakes the notification bar once a second:
// Put this in the onCreate method
pauseRefresh = new Runnable() {
@Override
public void run() {
// Check if media is playing to prevent race conditions
if (!isPlaying()) {
startForeground(FOREGROUND_SERVICE, notification);
demoteNotifyBar();
handler.postDelayed(pauseRefresh, 1000);
}
}
};
// Call this wherever you're handling the pause button
pauseRefresh.run();
To cancel the auto-refresh, you'll need to call this bit of code before you remake the notification bar and toggle the media from pause to playing (yes, you can ignore this for toggling audio, but read below for why this is needed):
handler.removeCallbacks(pauseRefresh);
You will also need to listen for the swipe dismiss with a delete intent, to prevent the notification from remaking itself when the user dismisses it; simply use the same code to cancel the timer that is used when the user clicks play.
回答3:
so you want when another application is playing their music you want your notification dismissable Right. you need to do is when you create notification (I guess in Mediaprepare() or click or something else), when you create the notification you set builder.setOngoing(true), and when you user pauses music or other application use media service you set builder.setOngoing(false) so user can easily dismiss your notification.
Happy Coding
回答4:
Did you tried to use
NotificationCompat.Builder()
...
.setOngoing(true)
...
.build()
?
Should do the trick.
Actually, you don't need to stop your foreground. Just use this setting. When you want to change this - just build new Notification with ongoing == false and then call it like:
notificationManager.notify( id, yourNotification )
来源:https://stackoverflow.com/questions/53502244/how-to-make-notification-dismissible-when-playing-music-in-background-like-in-sp