【问题标题】:How do I update the notification text for a foreground service in Android?如何更新 Android 中前台服务的通知文本?
【发布时间】:2011-07-28 13:11:17
【问题描述】:

我在 Android 中有一个前台服务设置。我想更新通知文本。我正在创建如下所示的服务。

如何更新在此前台服务中设置的通知文本?更新通知的最佳做法是什么?任何示例代码将不胜感激。

public class NotificationService extends Service {

    private static final int ONGOING_NOTIFICATION = 1;

    private Notification notification;

    @Override
    public void onCreate() {
        super.onCreate();

        this.notification = new Notification(R.drawable.statusbar, getText(R.string.app_name), System.currentTimeMillis());
        Intent notificationIntent = new Intent(this, AbList.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
        this.notification.setLatestEventInfo(this, getText(R.string.app_name), "Update This Text", pendingIntent);

        startForeground(ONGOING_NOTIFICATION, this.notification);

    }

我正在我的主要活动中创建服务,如下所示:

    // Start Notification Service
    Intent serviceIntent = new Intent(this, NotificationService.class);
    startService(serviceIntent);

【问题讨论】:

    标签: android service notifications foreground


    【解决方案1】:

    现有的答案似乎都没有显示如何处理完整的案例 - 如果是第一次调用,则 startForeground 但更新后续调用的通知。

    您可以使用以下模式来检测正确的大小写:

    private void notify(@NonNull String action) {
        boolean isForegroundNotificationVisible = false;
        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        StatusBarNotification[] notifications = notificationManager.getActiveNotifications();
        for (StatusBarNotification notification : notifications) {
            if (notification.getId() == FOREGROUND_NOTE_ID) {
                isForegroundNotificationVisible = true;
                break;
            }
        }
        Log.v(getClass().getSimpleName(), "Is foreground visible: " + isForegroundNotificationVisible);
        if (isForegroundNotificationVisible){
            notificationManager.notify(FOREGROUND_NOTE_ID, buildForegroundNotification(action));
        } else {
            startForeground(FOREGROUND_NOTE_ID, buildForegroundNotification(action));
        }
    }
    

    此外,您需要像其他答案一样构建通知和渠道​​:

    private Notification buildForegroundNotification(@NonNull String action) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createNotificationChannel();
        }
        //Do any customization you want here
        String title;
        if (ACTION_STOP.equals(action)) {
            title = getString(R.string.fg_notitifcation_title_stopping);
        } else {
            title = getString(R.string.fg_notitifcation_title_starting);
        }
        //then build the notification
        return new NotificationCompat.Builder(this, CHANNEL_ID)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle(title)
                .setOngoing(true)
                .build();
    }
    
    @RequiresApi(Build.VERSION_CODES.O)
    private void createNotificationChannel(){
        NotificationChannel chan = new NotificationChannel(CHANNEL_ID, getString(R.string.fg_notification_channel), NotificationManager.IMPORTANCE_DEFAULT);
        chan.setLightColor(Color.RED);
        chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        assert manager != null;
        manager.createNotificationChannel(chan);
    }
    

    【讨论】:

      【解决方案2】:

      我认为使用相同的唯一 ID 和带有新信息的 Notification 再次调用 startForeground() 会起作用,尽管我没有尝试过这种情况。

      更新:根据 cmets,您应该使用 NotifcationManager 更新通知,并且您的服务继续保持在前台模式。看看下面的答案。

      【讨论】:

      • 您能否给我举个例子,说明我如何从我的活动中调用它?我还没有找到关于如何在前台服务中调用方法的好示例。
      • @Luke:使用服务的模式有很多种,我不知道你的模式是什么。如果您调用startService() 将命令传递给服务,那么只需再次调用startService() 告诉它更新其文本。或者,如果您正在调用bindService(),请向您的 API 添加一个方法以让服务更新其文本。或者,考虑是否应该由服务本身来决定是否更新文本。或者,文本可能是服务具有侦听器的SharedPeference。不可能在摘要中给你准确的建议。
      • 进一步澄清:您不能cancel()startForeground() 设置通知。您必须删除服务本身的前台状态(如果您想让代码文本再次出现,请使用 stopForeground()。我浪费了几个小时,因为这些答案让我相信这实际上是可能的。
      • 我对这个答案投了反对票,因为它显然是错误的:developer.android.com/training/notify-user/managing.html 请@CommonsWare 考虑删除这个答案,因为你的高声誉分数使这个答案成为休闲浏览器的“神圣真理”。谢谢。
      • 对我不起作用(尽管我记得在以前的项目中使用过同样的方法)。使用 NotificationManager 按我的预期工作。
      【解决方案3】:

      在更新通知时改进 Android 8.0+ 中 Luca Manzo 的回答,它会发出声音并显示为单挑。
      为了防止你需要添加setOnlyAlertOnce(true)

      所以代码是:

      private static final int NOTIF_ID=1;
      
      @Override
      public void onCreate(){
              this.startForeground();
      }
      
      private void startForeground(){
              startForeground(NOTIF_ID,getMyActivityNotification(""));
      }
      
      private Notification getMyActivityNotification(String text){
              if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
              ((NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(
              NotificationChannel("timer_notification","Timer Notification",NotificationManager.IMPORTANCE_HIGH))
      }
      
              // The PendingIntent to launch our activity if the user selects
              // this notification
              PendingIntent contentIntent=PendingIntent.getActivity(this,
              0,new Intent(this,MyActivity.class),0);
      
              return new NotificationCompat.Builder(this,"my_channel_01")
              .setContentTitle("some title")
              .setContentText(text)
              .setOnlyAlertOnce(true) // so when data is updated don't make sound and alert in android 8.0+
              .setOngoing(true)
              .setSmallIcon(R.drawable.ic_launcher_b3)
              .setContentIntent(contentIntent)
              .build();
      }
      
      /**
       * This is the method that can be called to update the Notification
       */
      private void updateNotification(){
              String text="Some text that will update the notification";
      
              Notification notification=getMyActivityNotification(text);
      
              NotificationManager mNotificationManager=(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
              mNotificationManager.notify(NOTIF_ID,notification);
      }
      

      【讨论】:

      • 缺少关键字,应该有new NotificationChannel
      • 所以我们可以将任何数字传递给 notification_id ?除了 0?
      • @Wini 是的,notification_id 必须是整数。
      【解决方案4】:

      当您想更新由 startForeground() 设置的 Notification 时,只需构建一个新的通知,然后使用 NotificationManager 通知它。

      关键点是使用相同的通知ID。

      我没有测试重复调用 startForeground() 更新 Notification 的场景,但我认为使用 NotificationManager.notify 会更好。

      更新通知不会将服务从前台状态中移除(这只能通过调用 stopForground 来完成);

      例子:

      private static final int NOTIF_ID=1;
      
      @Override
      public void onCreate (){
          this.startForeground();
      }
      
      private void startForeground() {
          startForeground(NOTIF_ID, getMyActivityNotification(""));
      }
      
      private Notification getMyActivityNotification(String text){
          // The PendingIntent to launch our activity if the user selects
          // this notification
          CharSequence title = getText(R.string.title_activity);
          PendingIntent contentIntent = PendingIntent.getActivity(this,
                  0, new Intent(this, MyActivity.class), 0);
      
          return new Notification.Builder(this)
                  .setContentTitle(title)
                  .setContentText(text)
                  .setSmallIcon(R.drawable.ic_launcher_b3)
                  .setContentIntent(contentIntent).getNotification();     
      }
      
      /**
       * This is the method that can be called to update the Notification
       */
      private void updateNotification() {
          String text = "Some text that will update the notification";
      
          Notification notification = getMyActivityNotification(text);
      
          NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
          mNotificationManager.notify(NOTIF_ID, notification);
      }
      

      documentation 状态

      要设置通知以便更新通知,请使用 通过调用NotificationManager.notify() 通知ID。更新 在您发出此通知后,更新或创建 NotificationCompat.Builder 对象,构建一个 Notification 对象 它,并使用您之前使用的相同 ID 发出 Notification。 如果之前的通知仍然可见,系统会更新它 来自Notification 对象的内容。如果上一个 通知已关闭,创建新通知 而是。

      【讨论】:

      • 这是正确的答案!上面的答案是非常错误和误导的。您无需重新启动服务即可更新愚蠢的通知。
      • @Radu 虽然我同意这是最佳答案(它避免了 Commonsware 的答案所采用的稍长的代码路径),但您误解了 Commonsware 的答案 - start/stopForegound do not start/stop服务,它们只会影响其前景。
      • @Stevie 感谢 Stevie,您可能是对的。不过我也不会搞砸的!
      • 调用notify()startForeground() 都会导致调用onStartCommand()
      • 使用NotificationManager 更新startForeground 显示的通知的问题是调用stopForeground 将不再删除通知。再次调用startForeground 来更新它可以避免这个问题。
      【解决方案5】:

      这是在您的服务中执行此操作的代码。创建一个新通知,但要求通知管理器通知您在 startForeground 中使用的相同通知 ID。

      Notification notify = createNotification();
      final NotificationManager notificationManager = (NotificationManager) getApplicationContext()
          .getSystemService(getApplicationContext().NOTIFICATION_SERVICE);
      
      notificationManager.notify(ONGOING_NOTIFICATION, notify);
      

      完整的示例代码,您可以在这里查看:

      https://github.com/plateaukao/AutoScreenOnOff/blob/master/src/com/danielkao/autoscreenonoff/SensorMonitorService.java

      【讨论】:

      • 我不确定这是否会保持 startService 的前台状态。
      • @Daniel Kao 您的解决方案没有启动前台服务
      • 如果我错了,请纠正我,但人们是否可以否决这个答案,请更详细地说明它有什么问题?问题不是问如何启动前台服务,而是如何更新前台服务的通知。这实际上与人们同意的 Luca 相同的答案可以工作并保持前台状态。
      • @TheIT 它不起作用。对于foreground created 消息,通知的状态变为not foreground
      • 这将导致重复通知,因为 startForeground() 已被调用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-24
      • 1970-01-01
      • 2019-01-15
      • 2012-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多