21

我有一个媒体服务,它使用 startForeground() 在播放开始时显示通知。播放时有暂停/停止按钮,暂停时有播放/停止按钮。

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
// setup...

Notification n = mBuilder.build();

if (state == State.Playing) {
    startForeground(mId, n);
}
else {
    stopForeground(false);
    mNotificationManager.notify(mId, n);        
}

这里的问题是当我显示/更新处于暂停状态的通知时,应该允许您将其删除。mBuilder.setOngoing(false)似乎没有效果,因为以前的startForeground覆盖它。

stopForeground(true);使用相同的代码调用按预期工作,但通知会在它被销毁和重新创建时闪烁。有没有办法“更新”从 startForeground 创建的通知以允许在调用 stop 后将其删除?

编辑:根据要求,这是创建通知的完整代码。每当播放或暂停服务时都会调用 createNotification。

private void createNotification() {
    NotificationCompat.Builder mBuilder = 
            new NotificationCompat.Builder(this)
    .setSmallIcon(R.drawable.ic_launcher)
    .setContentTitle("No Agenda")
    .setContentText("Live stream");

    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
    {
        if (state == State.Playing) {
            Intent pauseIntent = new Intent(this, MusicService.class);
            pauseIntent.setAction(ACTION_PAUSE);
            PendingIntent pausePendingIntent =     PendingIntent.getService(MusicService.this, 0, pauseIntent, 0);              

            mBuilder.addAction(R.drawable.pause, "Pause", pausePendingIntent);
            //mBuilder.setOngoing(true);
        }
        else if (state == State.Paused) {
            Intent pauseIntent = new Intent(this, MusicService.class);
            pauseIntent.setAction(ACTION_PAUSE);
            PendingIntent pausePendingIntent =  PendingIntent.getService(MusicService.this, 0, pauseIntent, 0);

            mBuilder.addAction(R.drawable.play, "Play", pausePendingIntent);
            mBuilder.setOngoing(false);
        }

        Intent stopIntent = new Intent(this, MusicService.class);
        stopIntent.setAction(ACTION_STOP);
        PendingIntent stopPendingIntent = PendingIntent.getService(MusicService.this, 0, stopIntent, 0);

        setNotificationPendingIntent(mBuilder);
        mBuilder.addAction(R.drawable.stop, "Stop", stopPendingIntent);
    }
    else
    {
        Intent resultIntent = new Intent(this, MainActivity.class);
        PendingIntent intent = PendingIntent.getActivity(this, 0, resultIntent, 0);

        mBuilder.setContentIntent(intent);
    }

    Notification n = mBuilder.build();

    if (state == State.Playing) {
        startForeground(mId, n);
    }
    else {
        stopForeground(true);
        mNotificationManager.notify(mId, n);
    }
}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void setNotificationPendingIntent(NotificationCompat.Builder mBuilder) {
    Intent resultIntent = new Intent(this, MainActivity.class);

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    stackBuilder.addParentStack(MainActivity.class);
    stackBuilder.addNextIntent(resultIntent);

    PendingIntent resultPendingIntent =
            stackBuilder.getPendingIntent(
                0,
                PendingIntent.FLAG_UPDATE_CURRENT
            );

    mBuilder.setContentIntent(resultPendingIntent);
}

后续编辑:

下面的评论之一提到答案可能是“脆弱的”,而随着 Android 4.3 的发布,背后的行为startForeground已经发生了变化。startForeground 将强制您的应用程序在前台显示通知,并且应该只调用该方法并显示通知。我尚未测试,但接受的答案可能不再按预期工作。

在调用时停止闪烁方面stopForeground,我认为不值得为框架而战。

这里有一些关于 Android 4.3 通知更改的附加信息

4

4 回答 4

6

您可以考虑使用不同的方法。
由于您应该将前台服务用于此类任务(媒体播放),我建议您继续这样做start foreground(),但不要将通知传递给它,只需像这样设置 id 0 和通知 null startForeground(0, null);

这样前台服务就不会显示任何通知。

现在,为了您的目的,您可以使用常规通知并更新它们的状态(正在进行、布局、文本等),这样您就不必依赖前台服务的通知行为。

希望这可以帮助。

于 2013-04-02T13:41:39.943 回答
6

而不是stopService(true),调用stopService(false)将保留通知原样(没有正在进行的状态),除非它被用户解除/以编程方式删除或服务停止。因此只需调用 stopService(false) 并更新通知以显示暂停状态,现在通知可以被用户关闭。这也可以防止闪烁,因为我们没有重新创建通知。

于 2016-03-05T17:17:25.367 回答
3

根据文档,这种行为是在 Lollipop 之前设计的

针对此版本或更高版本的应用程序将获得这些新的行为变化:

...

  • 使用 removeNotification false 调用 Service.stopForeground 将修改仍然发布的通知,使其不再被迫持续。
于 2015-01-20T00:51:29.760 回答
1

在 N 之前,当 stopForeground 和 startForeground 依次调用时,通知必须重新出现。您需要再次显示通知,暂停后不要将其设为前台通知。我建议您不要添加解决方法或破解来解决此问题。(有解决方法,但可能会引入其他错误)。

在 N+ 上,添加了一个标志,ServiceCompat.STOP_FOREGROUND_DETACH。这将传递给 stopForeground 并让您将当前通知保留在通知托盘中。

也不要忘记终止服务(stopSelf() 或其他)。因为如果用户滑动应用程序,您的应用程序主进程可能会保留。

于 2020-09-24T21:20:23.280 回答