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>

运行效果

相关推荐
传奇开心果编程16 分钟前
【Compose Multiplatform 跨端开发学与练】第8课 资源管理与主题
android·windows·学习·ios·kotlin·web·composer
传奇开心果编程2 小时前
【Compose Multiplatform 跨端开发学与练】第9课 测试与调试
android·学习·macos·ios·kotlin·web·composer
传奇开心果编程2 小时前
【Compose Multiplatform 跨端开发学与练】第4课 导航与路由
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程2 小时前
【Compose Multiplatform 跨端开发学与练】第6课 状态管理与架构
android·学习·ui·ios·架构·kotlin·composer
事圆则缓2 小时前
Android AOSP 定制常见概念:源码目录、系统镜像与刷机流程
android
传奇开心果编程2 小时前
【Compose Multiplatform 跨端开发学与练】第2课 Compose 基础语法
android·windows·学习·ui·ios·kotlin·composer
supabc1233 小时前
Celium:连接 Windows、Mac、Linux 与 Android,让远程访问和设备管理更简单
android·linux·windows·macos·远程访问·网络管理·celium
Dovis(誓平步青云)3 小时前
导览音频切换太快,旧讲解不能覆盖新展品
android·前端·javascript·ecmascript·音视频·宠物
五彩小白20 小时前
自回归和上下文
android
事圆则缓1 天前
Android 多渠道打包实战:Product Flavors、签名、AAB 与发包校验
android