Android通知频道,通知点
在本教程中,我们将研究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)来显示/隐藏特定频道的点。
借助通知点,长按应用程序图标现在也可以显示/取消待处理的通知,如下所示。
请注意,待处理通知的计数也显示在"通知点"菜单中。