好的.我有一个问题,即在 Android Oreo中保留媒体播放器服务.根据这里的讨论: Android Oreo: Keep started background service alive without setting it foreground (but with a notification)? 在Android Oreo中处理媒体播
Android Oreo: Keep started background service alive without setting it foreground (but with a notification)?
在Android Oreo中处理媒体播放器服务的正确方法似乎是在媒体播放器暂停时存储状态信息,因此如果它被销毁,按下播放将创建一个新的媒体播放器并从它停止的地方开始.
我的问题是如何创建一个通知,当启动它的服务被销毁时不会被销毁.我没有运行任何代码来解除通知,但是当服务被破坏时,它仍然会自动被解雇.正如您在我的代码中看到的,我可以重建通知onDestroy,但我不喜欢它看起来的方式,因为用户可以看到它再次解雇和重建.
这是我的通知代码:
private void buildNotification() { Cat.d("building notification"); final MediaPlayerService context = this; RequestBuilder<Bitmap> requestBuilder = Glide.with(this).asBitmap() .load(R.mipmap.ic_launcher); NotificationCompat.Action action; if (mediaPlayer != null && mediaPlayer.isPlaying()) action = generateAction(R.drawable.ic_pause, "Pause"); else action = generateAction(R.drawable.ic_play_arrow, "Play"); int[] actionsInCompact; builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setSmallIcon(R.drawable.ic_navbooks_icon_black) //.setOnlyAlertOnce(true) .setContentTitle(book.getTitle()) .setContentText(book.getAuthor()) .setAutoCancel(false) .setContentIntent(PendingIntentHelper.getOpenMainActivityIntent(context, book.getId())) .setDeleteIntent(PendingIntentHelper.getStopServiceIntent(context)); if (SettingsUtil.GetNotificationSkip(context)) { builder.addAction(R.drawable.ic_skip_backward, "Skip Previous", PendingIntentHelper.getSkipBackwardIntent(context)) .addAction(R.drawable.ic_backward, "Rewind", PendingIntentHelper.getSeekBackwardIntent(context)) .addAction(action) .addAction(R.drawable.ic_forward, "Fast Forward", PendingIntentHelper.getSeekForwardIntent(context)) .addAction(R.drawable.ic_skip_forward, "Skip Next", PendingIntentHelper.getSkipForwardIntent(context)); actionsInCompact = new int[]{0, 1, 2, 3, 4}; } else { builder.addAction(R.drawable.ic_backward, "Rewind", PendingIntentHelper.getSeekBackwardIntent(context)) .addAction(action) .addAction(R.drawable.ic_forward, "Fast Forward", PendingIntentHelper.getSeekForwardIntent(context)); actionsInCompact = new int[]{0, 1, 2}; } builder.setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle() .setMediaSession(mediaSession.getSessionToken()) .setShowActionsInCompactView(actionsInCompact)); // Load a cover image if there isn't one loaded yet or the cover has changed if(cover == null || !book.getCover().equals(lastCover)) { lastCover = book.getCover(); mediaSession.setMetadata(new MediaMetadataCompat.Builder() .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, book.getTitle()) .putString(MediaMetadataCompat.METADATA_KEY_TITLE, book.getAuthor()) .build()); Glide.with(this) .asBitmap() .error(requestBuilder) .load(book.getCover()) .into(new SimpleTarget<Bitmap>() { @Override public void onResourceReady(Bitmap largeIcon, Transition transition) { Cat.d("Finished loading"); cover = largeIcon; // initBuilder builder.setLargeIcon(largeIcon); mediaSession.setMetadata(new MediaMetadataCompat.Builder() .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, largeIcon) .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, book.getTitle()) .putString(MediaMetadataCompat.METADATA_KEY_TITLE, book.getAuthor()) .build()); startNotification(); } }); } else { mediaSession.setMetadata(new MediaMetadataCompat.Builder() .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, cover) .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, book.getTitle()) .putString(MediaMetadataCompat.METADATA_KEY_TITLE, book.getAuthor()) .build()); if(cover != null) builder.setLargeIcon(cover); } startNotification(); } private NotificationCompat.Action generateAction(int icon, String title) { return new NotificationCompat.Action.Builder( icon, title, PendingIntentHelper.getPlayPauseIntent(this)).build(); } private void startNotification() { mediaSession.setPlaybackState(new PlaybackStateCompat.Builder() .setActions(MEDIA_SESSION_ACTIONS) .setState(mediaPlayer.isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED, book.getLastPosition(), 1) .build()); if(mediaPlayer.isPlaying()) startForeground(NOTIFICATION_ID, builder.build()); else { NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); if(notificationManager != null) { notificationManager.notify(NOTIFICATION_ID, builder.build()); } stopForeground(false); } }
以下是服务销毁时发生的情况:
@Override public void onDestroy() { //super.onDestroy(); handleDestroy(); } private void handleDestroy() { if(book != null) sendProgressUpdate(); else book = new BookDBHelper(this).getBook(SettingsUtil.GetLastPlayedBook(this)); if(mediaPlayer != null) { book.setLastPosition(this, getPosition()); SyncHelper.SendProgressUpdate(this, book); } if(mediaSession != null) mediaSession.release(); if(noisyRegistered) { unregisterReceiver(becomingNoisyReceiver); unregisterReceiver(shakeReceiver); } buildNotification(); }好的.我发现stopForeground函数有一个标志的可选参数而不是布尔值.可以给它一个标志STOP_FOREGROUND_DETACH,即使在调用stopForeground之后也需要从服务中分离通知,这样当服务被销毁时,通知将不会被解除,并且不需要构建新的通知.这是我更新的启动通知代码:
private void startNotification() { int NOTIFICATION_ID = 7853154; mediaSession.setPlaybackState(new PlaybackStateCompat.Builder() .setActions(MEDIA_SESSION_ACTIONS) .setState(mediaPlayer.isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED, book.getLastPosition(), 1) .build()); if(mediaPlayer.isPlaying()) startForeground(NOTIFICATION_ID, builder.build()); else { stopForeground(STOP_FOREGROUND_DETACH); NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); if(notificationManager != null) { notificationManager.notify(NOTIFICATION_ID, builder.build()); } } }