Android 允许在调用stopForeground后取消通知(false)

Android 允许在调用stopForeground后取消通知(false),android,android-service,android-notifications,android-notification-bar,Android,Android Service,Android Notifications,Android Notification Bar,我有一个媒体服务,它使用startForeground()在播放开始时显示通知。播放时有暂停/停止按钮,暂停时有播放/停止按钮 NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this); // setup... Notification n = mBuilder.build(); if (state == State.Playing) { startForeground(mId, n); }

我有一个媒体服务,它使用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.setContinuous(false)
似乎没有效果,因为前面的
startForeground
覆盖了它

调用<代码>停止前台(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将强制应用程序在前台显示通知,并且该方法只应在通知显示时调用。我还没有测试,但公认的答案可能不再像预期的那样有效

至于在调用
stopfrogent
时停止闪烁,我认为不值得为框架而战


<>有一些。

你可以考虑使用不同的方法。 既然您应该使用前台服务执行这样的任务(媒体播放),我建议您继续执行
启动前台()
,而不是向其传递通知,只需像这样设置id 0和通知null
启动前台(0,null)

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

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

希望这能有所帮助。

根据这一行为,棒棒糖是由事先设计好的

针对此版本或更高版本的应用程序将在行为上获得以下新更改:

  • 在removeNotification为false的情况下调用Service.stopForeground将修改仍然发布的通知,使其不再被迫进行

调用
stopService(false)
而不是
stopService(true)
,将保留通知的原样(无持续状态),除非用户以编程方式解除通知/删除通知或服务停止。因此,只需调用stopService(false)和updatenotification来显示暂停状态,现在用户就可以取消通知。这还可以防止闪烁,因为我们没有重新创建通知

在N之前,当按顺序调用stopForeground和startForeground时,通知必须重新出现。您需要再次显示通知,并且在暂停后不要将其设为前台通知。我建议您不要添加变通方法或黑客来修复此问题(有变通方法,但可能会引入其他bug)

在N+上,添加了一个标志ServiceCompat.STOP\u FOREGROUND\u DETACH。这将传递给stopForeground,并允许您将当前通知保存在通知托盘中


另外,不要忘记终止服务(stopSelf()或其他任何东西)。因为如果用户刷走应用程序,应用程序主进程可能会保留。

当您尝试调用
setconsuming(false)
时,能否显示您的代码?我怀疑没有重新生成通知以获取更改,但很难从这段代码中分辨出来。@dsandler我已经为createNotification()添加了完整的代码。我还想指出,我目前只在Jellybean上进行测试,目前是4.2.2(emulator和phone),这就是我设置SetContinuousing(false)的地方。此外,当通知未通过startForeground启动(且SetContinuous(true)未注释)时,SetContinuous(false)也可以工作。这听起来像是正确的路径,但是传递null通知会在startForeground()上引发IllegalArgumentException。下面的问题似乎也说明了同样的问题:这很有趣,因为我已经使用这个方法好几次了,只是用一个空白项目重新测试了它。我还通过查询
PackageManager
确保服务确实在前台运行。您还可以尝试在
startForeground(id,notification)
中将0作为id传递,使用0作为id,并且一切正常。除0之外的任何id似乎都会导致IllegalArgumentException。完美的看起来很脆弱。我似乎很清楚,谷歌希望前台服务有一个通知,所以我不会指望当前的行为在未来的Android版本中起作用。。。我建议使用stopForeground(true)并与通知flash一起使用。@jonasb@inistel正如jonasb最初所说的,这个答案可能是“脆弱的”,从Android 4.3开始,它可能不再工作,因为
startForeground
现在创建了自己的通知,如果没有传递通知来阻止恶意应用滥用前景状态。有关更多信息,请参见我问题底部的编辑。