Android通知频道,通知点

时间:2020-02-23 14:29:06  来源:igfitidea点击:

在本教程中,我们将研究Android Oreo的引入如何在通知方面带来了翻天覆地的变化。
您离Android Oreo更新不远。
开始之前,让我们研究一下通知的工作以及您需要进行哪些更改以及如何适应Android Developer。

Android通知频道

我们已经在这里和这里讨论并实现了Notification。

随着Android Oreo的推出,Google努力使Notifications系统更加用户友好。
Android Oreo完全重新设计了通知。
接收各种通知的权力已经在最终用户手中。
这一切成为可能的原因是:通知渠道。
通知渠道使我们可以将通知分为不同的组/类别。
每个通道将具有共同的功能。
它允许用户自定义其通知设置。

借助此功能,用户可以从"应用程序设置"中执行以下操作:

  • 阻止来自特定渠道的通知。

  • 在不同的通知渠道上设置优先级/静音。

Without configuring Notification Channels, you cannot build notification for applications with Android API >=26. Notification Channels would be ignored for older applications with the Android API < 26.Let's get down to the creation part.

建立通知频道

以下代码创建一个通知通道:

NotificationChannel notificationChannel = new NotificationChannel(channel_id , channel_name, NotificationManager.IMPORTANCE_HIGH);
              notificationChannel.enableLights(true);
              notificationChannel.enableVibration(true);
              notificationChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(notificationChannel);

NotificationChannel构造函数要求我们指定channel_id和channel_name字符串。
重要性参数是一个整数,它指定通知的中断级别。
它可以是以下值之一:

  • IMPORTANCE_DEFAULT –显示在系统托盘中。
    发出声音。
    不会从视觉上弹出。

  • IMPORTANCE_HIGH –也在视觉上弹出。

  • IMPORTANCE_LOW –显示在托盘中。
    没有弹出。
    没有声音。

  • IMPORTANCE_NONE-不显示。
    阻止通知的种类。

除了上面指定的公共方法外,以下是NotificationChannels附带的一些便捷方法。

  • setGroup()/getGroup()-通道的设置器和获取器。
    我们稍后再讨论。

  • setBypassDnd()?-将INTERRUPTION_PRIORITY_VALUE设置为不打扰。

  • canBypassDnd()–检查通知通道是否可以在DND模式下显示通知。

  • setLockScreenVisibility()–设置是否应在锁定屏幕上显示该频道的通知。

  • canShowBadge()–可以在应用程序图标上显示徽章/通知点。

  • getName()/getId()-分别获取频道名称和ID。

一旦使用createNotificationChannel()创建了通知通道,从它创建的每个通知将具有共同的属性,除非被修改。

注意:上面的代码段仅对Android版本Oreo及更高版本有效。
因此,必须将其包含在以下条件中。

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
}

创建通知

以下代码段从NotificationChannel创建一个Notification。

NotificationCompat.Builder notification = new NotificationCompat.Builder(this, "channel_id")
                          .setContentTitle("Test Title")
                          .setContentText("Test Message")
                          .setSmallIcon(R.mipmap.ic_launcher);

notificationManager.notify(1, notification.build());

在Android Oreo中,必须在Builder构造函数本身中指定NotificationChannelid

读取和删除通知通道

要检索通知通道,我们可以在NotificationManager上调用方法getNotificationChannel()。
我们需要传递相关频道的channel_id。
同样,要检索所有NotificationChannel的列表,我们可以调用方法getNotificationChannels()。

List<NotificationChannel> notificationChannels = notificationManager.getNotificationChannels();

删除NotificationChannel要删除NotificationChannel,请使用以下代码段。

notificationManager.deleteNotificationChannel("channel_id");

通知渠道组

NotificationChannelGroup用于为NotificationChannel创建不同的类别。
相同的NotificationChannels可以在不同的情况下使用,具体取决于调用它们的组。
您可以有两个名为"每小时","每日"的组。
所有通知通道都将出现在两个组中。
您可以选择要使用该频道创建通知的组。

创建NotificationChannelGroup

以下是创建NotificationChannelGroups的一种方法。

List<NotificationChannelGroup> list = new ArrayList<>();
          list.add(new NotificationChannelGroup(group_id_1, group_name_2));
          list.add(new NotificationChannelGroup(group_id_2, group_name_2));

          notificationManager.createNotificationChannelGroups(list);

您需要设置group_id和group_name。
此外,您还需要使用setGroup()在NotificationChannel上设置组。
在setGroup()方法中传入group_id。

通过设置修改通知

最终用户可以从"设置"中修改"通知通道"。
设置|应用程式|应用名称|应用通知

另外,我们可以使用Intents从应用程序本身重定向它们。

Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_CHANNEL_ID, notificationChannel.getId());
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
startActivity(intent);

我们传递频道ID和应用程序包名称。
这专门打开了特定的频道ID。

让我们创建一个具有NotificationChannel和NotificationChannelGroup用例的基本应用程序

项目结构

在此应用程序中,我们将使用RadioButton在组之间切换,并使用Spinners选择当前的NotificationChannel。
EditText将用于设置通知的正文。

Android NotificationChannel代码

下面给出了" activity_main.xml"布局文件的代码。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Choose the group for the channel"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent"
      android:padding="16dp"
      app:layout_constraintBottom_toTopOf="@+id/radioGroup"

  <RadioGroup
      android:id="@+id/radioGroup"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:padding="8dp"
      android:orientation="horizontal"
      android:weightSum="2"
      app:layout_constraintBottom_toTopOf="@+id/spinner"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent">

      <RadioButton
          android:id="@+id/radioButton1"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="First Type"
          android:layout_weight="1"
          android:textSize="18sp" 

      <RadioButton
          android:id="@+id/radioButton2"
          android:layout_width="wrap_content"
          android:layout_weight="1"
          android:layout_height="wrap_content"
          android:text="Second Type"
          android:textSize="18sp" 
  </RadioGroup>

  <Spinner
      android:id="@+id/spinner"
      style="@style/Widget.AppCompat.Spinner"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:padding="8dp"
      app:layout_constraintBottom_toTopOf="@+id/inContent"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent" 

  <EditText
      android:id="@+id/inContent"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:padding="8dp"
      android:hint="Enter message"
      app:layout_constraintBottom_toTopOf="@+id/btnNotification"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent" 

  <Button
      android:id="@+id/btnNotification"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Create New Notification"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent"
      app:layout_constraintTop_toTopOf="parent" 

</android.support.constraint.ConstraintLayout>

下面给出了MainActivity.java类的代码。

package com.theitroad.notificationchannels;

import android.app.AlertDialog;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Build;
import android.provider.Settings;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Spinner;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {

  List<String> data = new ArrayList<>();

  int notifier_counter = 0;
  NotificationManager notificationManager;
  RadioButton radioButtonFirst;
  RadioButton radioButtonSecond;
  RadioGroup radioGroup;
  EditText editText;
  Button btnNotification;
  Spinner spinner;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      initViews();
      notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

      data.add("Bitcoin");
      data.add("Ethereum");
      data.add("Litecoin");
      data.add("Ripple");

      createNotificationGroups();
      createNotificationChannels();

      ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, data);
      dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
      spinner.setAdapter(dataAdapter);
      spinner.setOnItemSelectedListener(this);

      radioGroup.check(R.id.radioButton1);

      btnNotification.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {

              if (editText.getText().toString().length() > 0) {
                  String channel_id = "";
                  String group_id = "";
                  PendingIntent contentIntent = PendingIntent.getActivity(MainActivity.this, 0, new Intent(MainActivity.this, MainActivity.class), 0);

                  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

                      RadioButton radioButton = findViewById(radioGroup.getCheckedRadioButtonId());
                      group_id = radioButton.getText().toString();
                      channel_id = notificationManager.getNotificationChannel(spinner.getSelectedItem().toString() + "_" + group_id).getId();
                      contentIntent = PendingIntent.getActivity(MainActivity.this, 0, new Intent(MainActivity.this, MainActivity.class).putExtra("importance", notificationManager.getNotificationChannel(channel_id).getImportance()).putExtra("channel_id", channel_id), PendingIntent.FLAG_UPDATE_CURRENT);
                  }

                  NotificationCompat.Builder notification = new NotificationCompat.Builder(MainActivity.this, channel_id)
                          .setContentTitle(spinner.getSelectedItem().toString())
                          .setContentText(editText.getText().toString())
                          .setGroup(group_id)
                          .setContentIntent(contentIntent)
                          .setSmallIcon(R.mipmap.ic_launcher);

                  notifier_counter++;
                  notificationManager.notify(notifier_counter, notification.build());
              } else {
                  Toast.makeText(getApplicationContext(), "Please enter something in EditText", Toast.LENGTH_LONG).show();
              }
          }
      });
  }

  @Override
  public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
  }

  @Override
  public void onNothingSelected(AdapterView<?> parent) {

  }

  private void initViews() {
      spinner = findViewById(R.id.spinner);
      btnNotification = findViewById(R.id.btnNotification);
      editText = findViewById(R.id.inContent);
      radioGroup = findViewById(R.id.radioGroup);
      radioButtonFirst = findViewById(R.id.radioButton1);
      radioButtonSecond = findViewById(R.id.radioButton2);
  }

  private void createNotificationGroups() {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
          List<NotificationChannelGroup> list = new ArrayList<>();
          list.add(new NotificationChannelGroup(radioButtonFirst.getText().toString(), radioButtonFirst.getText()));
          list.add(new NotificationChannelGroup(radioButtonSecond.getText().toString(), radioButtonSecond.getText()));

          notificationManager.createNotificationChannelGroups(list);

      }
  }

  private void createNotificationChannels() {
      for (String s : data) {
          if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {

              NotificationChannel notificationChannel = new NotificationChannel(s + "_" + radioButtonFirst.getText().toString(), s, NotificationManager.IMPORTANCE_HIGH);
              notificationChannel.enableLights(true);
              notificationChannel.enableVibration(true);
              notificationChannel.setGroup(radioButtonFirst.getText().toString());
              notificationChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});

              NotificationChannel notificationChannel2 = new NotificationChannel(s + "_" + radioButtonSecond.getText().toString(), s, NotificationManager.IMPORTANCE_NONE);
              notificationChannel2.enableLights(true);
              notificationChannel2.enableVibration(true);
              notificationChannel2.setGroup(radioButtonSecond.getText().toString());
              notificationChannel2.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});

              if (notificationManager != null) {
                  notificationManager.createNotificationChannel(notificationChannel);
                  notificationManager.createNotificationChannel(notificationChannel2);
              }
          }
      }
  }

  @Override
  protected void onNewIntent(Intent intent) {
      super.onNewIntent(intent);
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
          final Bundle bundle = intent.getExtras();
          int importance = -1;
          if (bundle != null) {
              importance = bundle.getInt("importance");
          }
          if (importance != -1) {

              AlertDialog.Builder alert = new AlertDialog.Builder(this);
              alert.setMessage("Goto settings to change the Notification channel")
                      .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                          @Override
                          public void onClick(DialogInterface dialog, int which) {
                              updateNotificationSettings(bundle.getString("channel_id"));
                          }
                      }).setNegativeButton("CANCEL", null)
                      .show();

          }

      }

  }

  private void updateNotificationSettings(String channel_id) {
      Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
      intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel_id);
      intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
      startActivity(intent);
  }

}

在上面的代码中,我们首先分别为RadioButtons和Spinners创建NotificationChannelGroup和NotificationChannel。

在channel_id后面附加有group_id以便知道该信道属于哪个组。

在"单击按钮"上,我们基于选择了哪个单选按钮和微调框来创建通知,并相应地检索channel_id和group_id。

在此示例中,默认情况下,我们已阻止来自属于第二组的所有渠道的通知。
(从设置中启用该频道以查看那些通知)。

单击通知后,我们将显示一个对话框,允许用户转到设置以更改当前的NotificationChannel设置。

在通知上,单击启动相同的活动。
因此,在列表文件中,我们需要在活动标记中设置android:launchMode =" singleTop"

输出

下面给出了上面应用程序的输出。

长按通知,它可以让我们使用滑块更改当前频道设置。

可见的"所有类别"选项使我们可以查看所有类型的频道和组。

请注意,我们从第一组和第二组切换了几个频道。
它导致第一个组中的通知被阻止,第二个组中的默认通知。

Android通知点

如果有未读的通知,则通知点/徽章将显示在应用程序图标上。

我们可以在通知中使用方法setShowBage(boolean)来显示/隐藏特定频道的点。

借助通知点,长按应用程序图标现在也可以显示/取消待处理的通知,如下所示。

请注意,待处理通知的计数也显示在"通知点"菜单中。