通知
通知为应用在未运行或处于后台时向用户传达消息提供了一种方式。例如,消息应用可能会发出通知,让用户知道有来自联系人的新消息到达。通知可分为本地通知和远程通知。本地通知由应用本身在其运行的设备上触发。另一方面,远程通知由远程服务器发起并传送到设备以供呈现给用户。通知出现在从屏幕状态栏下拉的通知抽屉中,每个通知可以包括诸如打开发送通知的应用的按钮等操作。Android 还支持直接回复通知,这一功能允许用户在通知面板内输入并提交对通知的响应。
当在 Android 设备上发起通知时,它会以图标的形式出现在状态栏中。
要查看通知,用户从状态栏开始向下滑动,以拉下通知抽屉
Android 8 及更高版本还支持通知点,当有通知等待用户查看时,这些通知点会出现在应用启动器图标上。一个典型的通知只会显示一条消息,当被点击时,会启动负责发出该通知的应用。通知也可能包含操作按钮,当被点击时,这些按钮会执行特定于相应应用的任务。例如,一个包含两个操作按钮的通知,允许用户删除或保存一条传入的消息。
在应用能够发送通知之前,它必须首先创建一个通知渠道。通知渠道由一个在应用内唯一标识该渠道的 ID、一个渠道名称和一个渠道描述组成(其中只有后两者会被用户看到)。通过配置 NotificationChannel 实例,然后将该对象传递给 NotificationManager 类的 createNotificationChannel()方法来创建渠道。
一个本地通知的简单实现
1、创建发送通知的Activity 第一步:
创建通知频道,配置通知频道的相关信息,Id、name和重要程度
light:表示呼吸灯相关
enableVibration:表示震动相关
100ms震动 → 200ms停 → 300ms震动...
java
protected void createNotificationChannel(String id, String name, String description) {
int importance = NotificationManager.IMPORTANCE_LOW;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(id, name, importance);
channel.setDescription(description);
channel.enableLights(true);
channel.setLightColor(Color.RED);
channel.enableVibration(true);
channel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
notificationManager.createNotificationChannel(channel);
}
}
第二步:
创建请求权限方法
通过ContextCompat.checkSelfPermission()
方法检测当前权限状态
返回值为PackageManager.PERMISSION_GRANTED
(已授权)或PERMISSION_DENIED
(未授权)
如果未授权,则调用ActivityCompat.requestPermissions()
方法进行权限的请求
ActivityCompat.requestPermissions()
接收三个参数:
第一个参数是Activity实例(否则无法弹出系统权限对话框)
第二个参数是权限字符串数组(支持批量请求多个权限)
第三个参数是自定义请求码,用于在回调中识别请求来源
java
protected void requestPermission(String permissionType, int requestCode) {
int permission = ContextCompat.checkSelfPermission(context, permissionType);
if (permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(context, new String[]{permissionType}, requestCode);
}
}
第三步:
重载请求权限方法
请求权限不通过进行提示
java
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == NOTIFICATION_REQUEST_CODE) {
if (grantResults.length == 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
// 权限被拒绝
Toast.makeText(context, "需要通知权限", Toast.LENGTH_SHORT).show();
}
}
}
第五步:
创建发送通知方法
1、通知唯一标识符,用于后续更新或取消通知
2、创建跳转 Intent(目标为你的通知要打开跳转页面的Activity)
3、创建延迟 Intent(用于用户点击后启动Activity)
4、创建动作,设置动作的属性
5、设置通知频道Id
6、创建通知对象
7、通过Manager发送通知
java
private void sendNotification() {
// 1. 通知唯一标识符,用于后续更新或取消通知
int notificationID = 101;
// 2. 创建跳转意图(目标为ResultActivity)
Intent resultIntent = new Intent(context, ResultActivity.class);
// 3. 创建延迟意图(用于用户点击后启动Activity)
// FLAG_UPDATE_CURRENT:如果已存在则更新内容
// FLAG_IMMUTABLE:Android 12+要求显式声明不可变标志
PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0,
resultIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
// 4. 创建通知动作按钮(需Android 4.1+)
NotificationCompat.Action action = new NotificationCompat.Action.Builder(
R.drawable.ic_launcher_foreground, // 动作图标
"查看", // 动作文本
resultPendingIntent // 点击动作的意图
).build();
// 5. 通知渠道ID(必须与创建的渠道ID一致,Android 8.0+必须配置)
String channelId = "com.greenfred.realNews";
// 6. 构建通知对象
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId)
.setContentTitle("号外号外") // 主标题(状态栏显示)
.setContentText("今天是个好日子") // 正文内容
.setSmallIcon(R.drawable.ic_launcher_foreground) // 必须设置的小图标(纯alpha通道)
.setPriority(NotificationCompat.PRIORITY_HIGH) // 设置优先级(Android7.1及以下有效)
.setContentIntent(resultPendingIntent) // 设置主内容点击意图
.setAutoCancel(true) // 点击后自动移除通知
.addAction(action) // 添加动作按钮(最多显示3个)
.setChannelId(channelId); // 显式设置渠道ID(兼容性处理)
Notification notification = builder.build();
// 7. 发送通知(需确保已创建通知渠道)
notificationManager.notify(notificationID, notification);
}
完整代码如下
java
package com.example.basepractice.base.notification;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.example.basepractice.R;
import com.example.basepractice.baseUI.basic.BasicActivity;
public class NotificationSendActivity extends BasicActivity {
private Button backButton;
private Button sendNotifyButton;
NotificationManager notificationManager;
private static final int NOTIFICATION_REQUEST_CODE = 101;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_notification_send);
setupUI();
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
createNotificationChannel("com.greenfred.realNews", "超级真新闻", "爱信不信");
requestPermission(android.Manifest.permission.POST_NOTIFICATIONS, NOTIFICATION_REQUEST_CODE);
}
private void sendNotification() {
int notificationID = 101;
Intent resultIntent = new Intent(context, ResultActivity.class);
PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
String channelId = "com.greenfred.realNews";
NotificationCompat.Action action = new NotificationCompat.Action.Builder(
R.drawable.ic_launcher_foreground,
"查看",
resultPendingIntent
).build();
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId)
.setContentTitle("号外号外")
.setContentText("今天是个好日子")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(resultPendingIntent)
.setAutoCancel(true)
.addAction(action)
.setChannelId(channelId);
Notification notification = builder.build();
notificationManager.notify(notificationID, notification);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == NOTIFICATION_REQUEST_CODE) {
if (grantResults.length == 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
// 权限被拒绝
Toast.makeText(context, "需要通知权限", Toast.LENGTH_SHORT).show();
}
}
}
protected void requestPermission(String permissionType, int requestCode) {
int permission = ContextCompat.checkSelfPermission(context, permissionType);
if (permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(context, new String[]{permissionType}, requestCode);
}
}
protected void createNotificationChannel(String id, String name, String description) {
int importance = NotificationManager.IMPORTANCE_LOW;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(id, name, importance);
channel.setDescription(description);
channel.enableLights(true);
channel.setLightColor(Color.RED);
channel.enableVibration(true);
channel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
notificationManager.createNotificationChannel(channel);
}
}
private void setupUI() {
backButton = findViewById(R.id.back);
backButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
sendNotifyButton = findViewById(R.id.notify_button);
sendNotifyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendNotification();
}
});
}
}
通知的跳转的页面
java
package com.example.basepractice.base.notification;
import android.os.Bundle;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.example.basepractice.R;
import com.example.basepractice.baseUI.basic.BasicActivity;
public class ResultActivity extends BasicActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_result);
}
}
xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".base.notification.ResultActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="今天是个好日子"
>
</TextView>
</androidx.constraintlayout.widget.ConstraintLayout>
运行效果