In this tutorial, we’ll be looking into how the introduction of Android Oreo has brought a drastic change in the Notifications. You aren’t far away from getting an Android Oreo update. Before you do get, let’s look into the working of notifications and what you need to change and adapt as Android Developer.
在本教程中,我们将研究Android Oreo的引入如何在Notifications中带来了翻天覆地的变化。 您离Android Oreo更新不远。 在获得通知之前,让我们研究一下通知的工作以及需要更改和适应作为Android Developer的内容。
We have discussed and implemented Notification, here and here.
我们已经在这里和这里讨论并实现了Notification 。
With the introduction of Android Oreo, Google has strived the Notifications system more user-friendly. Android Oreo has completely redesigned notifications. The power to receive the kinds of notifications has been given in the hands of the end users. The reason this all became possible is: Notification Channels.
随着Android Oreo的推出,Google努力使Notifications系统更加用户友好。 Android Oreo完全重新设计了通知。 接收各种通知的权力已经在最终用户手中。 所有这一切成为可能的原因是: 通知渠道 。
通知渠道使我们可以将通知分为不同的组/类别。 每个通道将具有共同的功能。 它允许用户自定义其通知设置。
Thanks to this feature the user can do the following things from the Apps Settings:
借助此功能,用户可以从“应用程序设置”中执行以下操作:
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.
如果不配置通知通道,则无法为Android API> = 26的应用程序构建通知。 对于Android API <26的旧版应用程序,通知通道将被忽略。让我们进入创建部分。
Following code creates a notification channel:
以下代码创建一个通知通道:
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);
The NotificationChannel constructor requires us to specify the channel_id and channel_name strings. The Importance argument is an int which specifies the level of interruption by the notification. It can be one of the following values:
NotificationChannel构造函数要求我们指定channel_id和channel_name字符串。 重要性参数是一个整数,它指定通知的中断级别。 它可以是下列值之一:
Besides the public methods specified above, following are some handy methods that come with NotificationChannels.
除了上面指定的公共方法外,以下是NotificationChannels附带的一些便捷方法。
setGroup()
/getGroup()
– Setters and getters for the channel. We’ll look at this later. setGroup()
/ getGroup()
–通道的设置器和获取器。 我们待会再看。 ?
?
setBypassDnd()
?- Set the INTERRUPTION_PRIORITY_VALUE to bypass do not disturb. setBypassDnd()
?-将INTERRUPTION_PRIORITY_VALUE设置为不打扰。 canBypassDnd()
– Check whether the notification channel can display notification in DND mode. canBypassDnd()
–检查通知通道是否可以在DND模式下显示通知。 setLockScreenVisibility()
– Set whether notifications from this channel should be displayed on the lock screen or not. setLockScreenVisibility()
–设置是否应在锁定屏幕上显示此通道的通知。 canShowBadge()
– Can show the badge/notification dot on the application icon. canShowBadge()
–可以在应用程序图标上显示徽章/通知点。 getName()
/getId()
– Retrieve the channel name and id respectively. getName()
/ getId()
–分别获取通道名称和ID。 Once the Notification Channel is created using createNotificationChannel()
, every notification created from it will have common properties unless modified.
使用createNotificationChannel()
创建通知通道后,从其中创建的每个通知都将具有公共属性,除非进行了修改。
Note: The above code snippet is valid for Android version Oreo and above only. Hence it must be enclosed in the following condition.
注意:上面的代码段仅对Android版本Oreo及更高版本有效。 因此,必须将其放在以下条件中。
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
}
The following code snippet creates a Notification from NotificationChannel.
以下代码段从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());
From Android Oreo, it is mandatory to specify the NotificationChannel id
in the Builder constructor itself.
在Android Oreo中,必须在Builder构造函数本身中指定NotificationChannel id
。
To retrieve a notification channel we can call the method getNotificationChannel() on the NotificationManager.
We need to pass the channel_id of the relevant channel.
Also, to retrieve a list of all NotificationChannels we can invoke the method getNotificationChannels().
要检索通知通道,我们可以在NotificationManager上调用方法getNotificationChannel()。
我们需要传递相关频道的channel_id。
同样,要检索所有NotificationChannel的列表,我们可以调用方法getNotificationChannels()。
List notificationChannels = notificationManager.getNotificationChannels();
Deleting a NotificationChannel
To delete a NotificationChannel, the following snippet is used.
删除NotificationChannel
要删除NotificationChannel,请使用以下代码段。
notificationManager.deleteNotificationChannel("channel_id");
A NotificationChannelGroup is used to created different categories for NotificationChannels.
The same NotificationChannels can be used in different circumstances depending on the group from which they are invoked.
You can have two groups named Hourly, Daily. All the Notification Channels would be present in both the groups. It’s your choice from which group you want to use the channel to create Notifications.
NotificationChannelGroup用于为NotificationChannel创建不同的类别。
相同的NotificationChannels可以在不同的情况下使用,具体取决于调用它们的组。
您可以有两个名为“每小时”,“每日”的组。 所有通知通道都将出现在两个组中。 您可以从哪个组中选择使用该通道来创建通知。
Following is one way to create NotificationChannelGroups.
以下是创建NotificationChannelGroups的一种方法。
List 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);
You need to set the group_id and group_name.
Furthermore, you need to set the group on the NotificationChannel too using setGroup()
. Pass in the group_id in the setGroup() method.
您需要设置group_id和group_name。
此外,您还需要使用setGroup()
在NotificationChannel上设置组。 在setGroup()方法中传递group_id。
The end user can modify the Notification Channel from the Settings.
Settings | Apps | App Name | App Notifications
最终用户可以从“设置”中修改“通知通道”。
设置| 应用程式| 应用名称| 应用程序提醒
Alternatively we can redirect them from the app itself using Intents.
另外,我们可以使用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);
We pass the channel id and app package name. This specifically opens the particular channel ID.
我们传递频道ID和应用程序包名称。 这专门打开了特定的通道ID。
Let’s create a basic application with the use cases of NotificationChannel and NotificationChannelGroup
让我们使用NotificationChannel和NotificationChannelGroup的用例创建一个基本应用程序
In this application, we’ll be using RadioButton to change between the groups and Spinners to choose the current NotificationChannel. The EditText would be used to set the body of the notification.
在此应用程序中,我们将使用RadioButton在组之间切换,并使用Spinners选择当前的NotificationChannel。 EditText将用于设置通知的正文。
The code for the activity_main.xml
layout file is given below.
下面给出了activity_main.xml
布局文件的代码。
The code for the MainActivity.java class
is given below.
下面给出MainActivity.java class
的代码。
package com.journaldev.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 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 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 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);
}
}
In the above code, we begin by creating the NotificationChannelGroup and NotificationChannel for the RadioButtons and Spinners respectively.
在上面的代码中,我们首先分别为RadioButtons和Spinners创建NotificationChannelGroup和NotificationChannel。
The channel_id
is appended with the group_id
in order to know which group does the channel belong to.
channel_id
附加有group_id
,以便知道该通道属于哪个组。
On Button click we create the notification based on which radio button and spinners were selected and retrieve the channel_id and group_id accordingly.
在“单击按钮”上,我们基于选择了哪个单选按钮和微调框来创建通知,并相应地检索channel_id和group_id。
For this example, by default, we’ve blocked notifications from all the channels belonging to second group.
(Enable that channel from the settings to view those notifications).
对于此示例,默认情况下,我们已阻止来自属于第二组的所有渠道的通知。
(从设置中启用该频道以查看那些通知)。
On a notification click, we show up a dialog that allows the user to goto the settings to change the current NotificationChannel settings.
单击通知后,我们将显示一个对话框,允许用户转到设置以更改当前的NotificationChannel设置。
On Notification click launches the same activity. Hence in the Manifest file we need to set android:launchMode="singleTop"
in the activity tag.
在通知上,单击启动相同的活动。 因此,在清单文件中,我们需要在活动标记中设置android:launchMode="singleTop"
。
The output of the above application in action is given below.
下面给出了上面应用程序的输出。
Long Press on a Notification, it allows us to change the current channel settings with the slider.
长按通知,它可以让我们使用滑块更改当前频道设置。
The All categories option that’s visible lets us view all types of channels and groups.
可见的“所有类别”选项使我们可以查看所有类型的渠道和群组。
Do take note that we’d toggled a few channels from the first and second group. It lead to blocked notifications in the first group and default notifications in the second.
请注意,我们从第一组和第二组切换了几个通道。 它导致第一个组中的通知被阻止,第二个组中的默认通知。
Notification Dots/Badges are displayed on the app icon if there are unread notifications.
如果有未读的通知,则通知点/徽章将显示在应用程序图标上。
We can use the method setShowBage(boolean)
on the notification to display/hide the dot for the particular channel.
我们可以在通知中使用setShowBage(boolean)
方法来显示/隐藏特定频道的点。
Thanks to Notification Dots, long pressing the app icon can now display/cancel the pending notifications too as shown below.
借助通知点,长按应用程序图标现在也可以显示/取消待处理的通知,如下所示。
Do note that the count for the pending notifications is displayed in the Notification Dot menu too.
请注意,待处理通知的计数也显示在“通知点”菜单中。
This brings an end to this tutorial. You can download the final Android NotificationChannels Project from the link below.
本教程到此结束。 您可以从下面的链接下载最终的Android NotificationChannels项目 。
翻译自: https://www.journaldev.com/19421/android-notification-channel-dots