Android一些基础-08-一个简单的通知

通知

通知为应用在未运行或处于后台时向用户传达消息提供了一种方式。例如,消息应用可能会发出通知,让用户知道有来自联系人的新消息到达。通知可分为本地通知和远程通知。本地通知由应用本身在其运行的设备上触发。另一方面,远程通知由远程服务器发起并传送到设备以供呈现给用户。通知出现在从屏幕状态栏下拉的通知抽屉中,每个通知可以包括诸如打开发送通知的应用的按钮等操作。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>

运行效果

相关推荐
robotx1 小时前
安卓线程相关
android
消失的旧时光-19431 小时前
Android 面试高频:JSON 文件、大数据存储与断电安全(从原理到工程实践)
android·面试·json
dalancon2 小时前
VSYNC 信号流程分析 (Android 14)
android
dalancon2 小时前
VSYNC 信号完整流程2
android
dalancon2 小时前
SurfaceFlinger 上帧后 releaseBuffer 完整流程分析
android
用户69371750013843 小时前
不卷AI速度,我卷自己的从容——北京程序员手记
android·前端·人工智能
程序员Android4 小时前
Android 刷新一帧流程trace拆解
android
墨狂之逸才4 小时前
解决 Android/Gradle 编译报错:Comparison method violates its general contract!
android
阿明的小蝴蝶5 小时前
记一次Gradle环境的编译问题与解决
android·前端·gradle
汪海游龙5 小时前
开源项目 Trending AI 招募 Google Play 内测人员(12 名)
android·github