【问题标题】:Android O - Notification Channels and NotificationCompatAndroid O - 通知通道和 NotificationCompat
【发布时间】:2017-07-10 15:18:13
【问题描述】:

我无法改变这种感觉:再次,Android 开发人员想出了一些新东西,让每个人都对他们认为如何使用该功能一无所知。

我说的是 Android O 中的通知通道。

多年来,我一直在使用兼容性支持库来避免处理特定的平台细节。即:NotificationCompat

现在,Builder 要求我提供一个通知频道 ID,这很好,但完全让我独自创建这样一个频道。我找不到任何对创建频道的兼容支持。我也找不到合理的方法在正确的位置创建它们。

文档只是声明它应该在“某处”完成并且“在发出通知时可能不会”。但我究竟应该怎么做?我讨厌为简单的任务编写特定于版本的东西——这就是我使用兼容库的原因。

有人对如何处理它有建议吗?每次我想要显示通知时都进行创建是否“昂贵”?

【问题讨论】:

  • “我也找不到合理的方法在正确的位置创建它们”——我会在你的应用程序第一次运行时这样做,或者如果它们不存在则根据需要延迟创建. “每次我想要显示通知时都进行创建是否“昂贵”? -- 每次创建相同的频道充其量是一种浪费,或者最坏的情况是给你 N 组频道,因为没有更新机制。 “我找不到任何对创建频道的兼容支持”——v26 库处于测试阶段;也许他们会添加它。

标签: java android-notifications android-support-library android-8.0-oreo


【解决方案1】:

这是我在 Android O 上生成通知并保持向后兼容性的解决方案:

        String idChannel = "my_channel_01";
        Intent mainIntent;

        mainIntent = new Intent(context, LauncherActivity.class);

        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, mainIntent, 0);

        NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        NotificationChannel mChannel = null;
        // The id of the channel.

        int importance = NotificationManager.IMPORTANCE_HIGH;

        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, null);
        builder.setContentTitle(context.getString(R.string.app_name))
                .setSmallIcon(getNotificationIcon())
                .setContentIntent(pendingIntent)
                .setContentText(context.getString(R.string.alarm_notification) + ManagementDate.getIstance().hourFormat.format(getAlarm(context, 0)));

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            mChannel = new NotificationChannel(idChannel, context.getString(R.string.app_name), importance);
            // Configure the notification channel.
            mChannel.setDescription(context.getString(R.string.alarm_notification));
            mChannel.enableLights(true);
            mChannel.setLightColor(Color.RED);
            mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
            mNotificationManager.createNotificationChannel(mChannel);
        } else {
            builder.setContentTitle(context.getString(R.string.app_name))
                    .setPriority(NotificationCompat.PRIORITY_HIGH)
                    .setColor(ContextCompat.getColor(context, R.color.transparent))
                    .setVibrate(new long[]{100, 250})
                    .setLights(Color.YELLOW, 500, 5000)
                    .setAutoCancel(true);
        }
        mNotificationManager.notify(1, builder.build());

【讨论】:

    【解决方案2】:

    它没有你想象的那么贵! 您需要做的就是创建一个通知通道并将其绑定到通知。

    您可以通过两种方式解决此问题,但对于这两种方式,您都需要创建一个具有特定频道 ID 的通知频道。

    NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    String id = "my_channel_01";
    int importance = NotificationManager.IMPORTANCE_LOW;
    NotificationChannel mChannel = new NotificationChannel(id, name,importance);
    mChannel.enableLights(true);
    mNotificationManager.createNotificationChannel(mChannel);
    

    第一种方法是在构造函数中设置通知通道:

    Notification notification = new Notification.Builder(MainActivity.this , id).setContentTitle("Title");
    mNotificationManager.notify("your_notification_id", notification);
    

    第二种方法是通过Notificiation.Builder.setChannelId()设置频道

    Notification notification = new Notification.Builder(MainActivity.this).setContentTitle("Title").
    setChannelId(id);
    mNotificationManager.notify("your_notification_id", notification);
    

    希望对你有帮助

    【讨论】:

    • 这是用于通知,而不是用于 NotificationCompat
    • 如果我为应用程序设置了通知通道,是否有可能获得我为特定应用程序更改的声音URI。在频道的帮助下
    【解决方案3】:

    这是一个替代解决方案,它使用 reflection 创建通知通道,因此您可以将compileSdkVersion 设置为低于 26。

       private void createNotificationChannel(NotificationManager notificationManager) {
            // Channel details
            String channelId = "myChannelId";
            String channelName = "Notifications";
    
            // Channel importance (3 means default importance)
            int channelImportance = 3;
    
            try {
                // Get NotificationChannel class via reflection (only available on devices running Android O or newer)
                Class notificationChannelClass = Class.forName("android.app.NotificationChannel");
    
                // Get NotificationChannel constructor
                Constructor<?> notificationChannelConstructor = notificationChannelClass.getDeclaredConstructor(String.class, CharSequence.class, int.class);
    
                // Instantiate new notification channel
                Object notificationChannel = notificationChannelConstructor.newInstance(channelId, channelName, channelImportance);
    
                // Get notification channel creation method via reflection
                Method createNotificationChannelMethod =  notificationManager.getClass().getDeclaredMethod("createNotificationChannel", notificationChannelClass);
    
                // Invoke method on NotificationManager, passing in the channel object
                createNotificationChannelMethod.invoke(notificationManager, notificationChannel);
    
                // Log success to console
                Log.d("MyApp", "Notification channel created successfully");
            }
            catch (Exception exc) {
                // Log exception to console
                Log.e("MyApp", "Creating notification channel failed", exc);
            }
        }
    

    然后,当您构建通知时,只需调用NotificationCompat.Builder.setChannelId() 方法:

    builder.setChannelId("myChannelId");
    

    注意:您需要将appcompat-v7 库更新到build.gradle 中的26.x.x 版本:

    compile 'com.android.support:appcompat-v7:26.1.0'
    

    【讨论】:

      【解决方案4】:

      如果您想支持以前版本的 Android (NotificationManager 以在NotificationHelper 中创建和构建Notification.Builder 实例,如下所示:

      /**
       * Helper class to manage notification channels, and create notifications.
       * <p>
       * Created by teocci.
       *
       * @author teocci@yandex.com on 2018-Oct-02
       */
      public class NotificationHelper extends ContextWrapper
      {
          public static final String NOTIFICATION_CHANNEL_PRIMARY = "notification_channel_primary";
          public static final int NOTIFICATION_ID_PRIMARY = 1100;
      
          private NotificationManager manager;
      
          /**
           * Registers notification channels, which can be used later by individual notifications.
           *
           * @param ctx The application context
           */
          public NotificationHelper(Context ctx)
          {
              super(ctx);
      
              // For API 26+ create notification channels
              if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                  NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_PRIMARY,
                          getString(R.string.channel_name),
                          NotificationManager.IMPORTANCE_DEFAULT
                  );
                  channel.setLightColor(Color.BLUE);
                  channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
                  channel.setDescription(getString(R.string.channel_description));
                  getManager().createNotificationChannel(channel);
              }
          }
          /**
           * Cancel a previously shown notification.  If it's transient, the view
           * will be hidden.  If it's persistent, it will be removed from the status
           * bar.
           *
           * @param id    The ID of the notification
           */
          public void remove(int id){
              manager.cancel(id);
          }
      
          /**
           * Get a notification of type 1
           * <p>
           * Provide the builder rather than the notification it's self as useful for making notification
           * changes.
           *
           * @return the builder as it keeps a reference to the notification (since API 24)
           */
          public Notification getNotification()
          {
              return getNotification(getTitle(), getBody()).build();
          }
      
          /**
           * Get a notification of type 1
           * <p>
           * Provide the builder rather than the notification it's self as useful for making notification
           * changes.
           *
           * @param title the title of the notification
           * @param body  the body text for the notification
           * @return the builder as it keeps a reference to the notification (since API 24)
           */
          public Notification.Builder getNotification(String title, String body)
          {
              Notification.Builder builder = new Notification.Builder(getApplicationContext())
                      .setOngoing(true)  // Persistent notification!
                      .setAutoCancel(true)
                      .setTicker(title)
                      .setContentTitle(title)
                      .setContentText(body)
                      .setSmallIcon(getSmallIcon());
      
              // Set the Channel ID for Android O.
              if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                  builder.setChannelId(NOTIFICATION_CHANNEL_PRIMARY); // Channel ID
              }
      
              return builder;
          }
      
          /**
           * Send a notification.
           *
           * @param id           The ID of the notification
           * @param notification The notification object
           */
          public void notify(int id, Notification.Builder notification)
          {
              getManager().notify(id, notification.build());
          }
      
          /**
           * Get the notification manager.
           * <p>
           * Utility method as this helper works with it a lot.
           *
           * @return The system service NotificationManager
           */
          private NotificationManager getManager()
          {
              if (manager == null) {
                  manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
              }
      
              return manager;
          }
      
          /**
           * Get the small icon for this app
           *
           * @return The small icon resource id
           */
          private int getSmallIcon()
          {
              return R.drawable.ic_smart_audio_noti_icon;
          }
      
          /**
           * Get the notification title for this app
           *
           * @return The notification title as string
           */
          private String getTitle()
          {
              return getString(R.string.notification_title);
          }
      
          /**
           * Get the notification content for this app
           *
           * @return The notification content as string
           */
          private String getBody()
          {
              return getString(R.string.notification_content);
          }
      }
      

      那么我们就可以像这样轻松使用它了:

      @Override
      public void onCreate()
      {
          ...
          notificationHelper = new NotificationHelper(this);
          notificationHelper.notify(NotificationHelper.NOTIFICATION_ID_PRIMARY, "App is running");
          ...
      }
      
      @Override
      public void onDestroy()
      {
          notificationHelper.remove(NotificationHelper.NOTIFICATION_ID_PRIMARY)
      }
      

      【讨论】:

        【解决方案5】:

        如果您的通知代码每次都具有相同的结构,那么您应该创建一个静态方法并传递所有您想要的并将检查此方法中的 API 级别 的代码。

        【讨论】:

          【解决方案6】:

          使用 NotificationChannnel 非常简单。

          NotificationChannel 实际上将多个通知分组到频道中。它基本上为用户提供了对通知行为的更多控制。您可以在Working with Notification Channel | With Example 阅读有关通知通道及其实现的更多信息

          创建通知渠道

           // This is the Notification Channel ID. More about this in the next section
          public static final String NOTIFICATION_CHANNEL_ID="channel_id";
          
          //User visible Channel Name
          public static final String CHANNEL_NAME="Notification Channel";
          
          // Importance applicable to all the notifications in this Channel
          int importance=NotificationManager.IMPORTANCE_DEFAULT;
          
          //Notification channel should only be created for devices running Android 26
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
          
                NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, CHANNEL_NAME, importance);
          
                //Boolean value to set if lights are enabled for Notifications from this Channel
                notificationChannel.enableLights(true);
          
                //Boolean value to set if vibration is enabled for Notifications from this Channel
                notificationChannel.enableVibration(true);
          
                //Sets the color of Notification Light
                notificationChannel.setLightColor(Color.GREEN);
          
                //Set the vibration pattern for notifications. Pattern is in milliseconds with the format {delay,play,sleep,play,sleep...}
                notificationChannel.setVibrationPattern(new long[]{500,500,500,500,500});
          
                //Sets whether notifications from these Channel should be visible on Lockscreen or not
                notificationChannel.setLockscreenVisibility( 
           Notification.VISIBILITY_PUBLIC);
          }
          // Creating the Channel
          NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
          notificationManager.createNotificationChannel(notificationChannel);
          

          现在在创建通知时,只需将通道 ID 传递给 Notification Builder 构造函数,如下所示

          //We pass the unique channel id as the second parameter in the constructor
          NotificationCompat.Builder notificationCompatBuilder=new NotificationCompat.Builder(this,NOTIFICATION_CHANNEL_ID);
          
          //Title for your notification
          notificationCompatBuilder.setContentTitle("This is title");
          
          //Subtext for your notification
          notificationCompatBuilder.setContentText("This is subtext");
          
          //Small Icon for your notificatiom
          notificationCompatBuilder.setSmallIcon(R.id.icon);
          
          //Large Icon for your notification 
          notificationCompatBuilder.setLargeIcon(  BitmapFactory.decodeResource(getResources(),R.id.icon));
          
          notificationManager.notify( NOTIFICATION_ID,notificationCompatBuilder.build());
          

          随着上述通知成为第一步创建的通知通道的一部分,其行为现在将与通道设置相关

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-02-27
            • 1970-01-01
            • 2017-12-18
            • 1970-01-01
            • 2019-10-11
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多