1. 通知
1.1 用法一覽
實現通知步驟
一般實現通知需要如下步驟:
-
1.獲取 NotificationManager 實例管理通知;
-
2.實例 Notification 對象;
-
低於Android 8.0 ((已經廢棄))
Notification notification = new NotificationCompat.Builder(MainActivity.this) -
高於Android 8.0
Notification notification = new NotificationCompat.Builder(MainActivity.this,"通知渠道Id")
-
-
3.管理事件 Intent(可帶要傳的參數),PendingItent;
-
4.發送通知。
-
5.關閉通知:自動或手動
注:如不需在通知出現時,點擊時有事件執行,步驟3可以忽略。
2. 低於 Android 8.0 的通知
新建一個項目【NotifationDemo】:
- 添加依賴包
,在文件app->build.gradle
中添加:
dependencies {
......
implementation 'com.android.support:support-v4:28.0.0'
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button android:id="@+id/btn_send_notifation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="發送通知"/>
</LinearLayout>
MainActivity.java
-
獲取通知管理器
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
-
創建通知對象
NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this); Notification notification = builder .setContentTitle("通知標題") .setContentText("通知內容") .setSmallIcon(R.mipmap.ic_launcher) //小圖標 .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_round)) //大圖標 .build();
-
發送通知
//發送通知: //第一個參數:是通知的Id,可用此id進行手動關閉 notificationManager.notify(AppConstant.NotificationId_Goto_NotifationActivity, notification);
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn_send_notifation = findViewById(R.id.btn_send_notifation);
btn_send_notifation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this);
Notification notification = builder
.setContentTitle("通知標題")
.setContentText("通知內容")
.setSmallIcon(R.mipmap.ic_launcher) //小圖標
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_round)) //大圖標
.setAutoCancel(true) //設置點擊通知后自動刪除通知
.build();
//發送通知:
//第一個參數:是通知的Id,可用此id進行手動關閉
notificationManager.notify(AppConstant.NotificationId_Goto_NotifationActivity, notification);
}
});
}
}
效果:點擊發送按鈕
- 狀態欄:內容小圖標
小圖標是空白,原因是沒有做 >=Android8.0(sdk>+26)
圖標適配,參見: 一起來學習Android 8.0系統的通知欄適配吧
- 通知內容
3.通知渠道(>=Android8.0(sdk>+26)的通知)
上面的代碼適用於Android的低版本,當版本高於8.0(sdk>+26)以后,就會無法彈出通知,因為在8.0中所有通知的實現都需要提供通知渠道
,否則,所有通知在8.0系統上面都不能正常顯示,原本的方法被遺棄:
NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this);
從Android 8.0系統開始,Google引入了通知渠道這個概念。
什么是通知渠道呢?顧名思義,就是每條通知都要屬於一個對應的渠道。每個App都可以自由地創建當前App擁有哪些通知渠道,但是這些通知渠道的控制權都是掌握在用戶手上的。用戶可以自由地選擇這些通知渠道的重要程度,是否響鈴、是否振動、或者是否要關閉這個渠道的通知。 詳情參見
一起來學習Android 8.0系統的通知欄適配吧
其它一些安卓的通知適配資料 :
https://blog.csdn.net/qq_37206616/article/details/87991525
示例:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button android:id="@+id/btn_send_notification"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="發送通知(小於Android 8.0)"/>
<Button android:id="@+id/btn_send_notification_chat"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="發送渠道通知:聊天類別"/>
<Button android:id="@+id/btn_send_notification_subcribe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="發送渠道通知:訂閱類別"/>
</LinearLayout>
- 創建
AppConstant
類: 通知Id,渠道Id統一放這里
public class AppConstant {
public static final int NotificationId_Goto_NotifationActivity = 1;
public static final int NotificationId_Chat = 2;
public static final int NotificationId_Subcribe = 3;
public static final String ChannelId_Chat = "ChannelId_Chat";
public static final String ChannelId_Subcribe = "ChannelId_Subcribe";
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initNotificationChannel();
//發送通知(< Andriod 8.0)
Button btn_send_notification = findViewById(R.id.btn_send_notification);
btn_send_notification.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this);
Notification notification = builder
.setContentTitle("通知標題")
.setContentText("通知內容")
.setSmallIcon(R.mipmap.ic_launcher) //小圖標
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_round)) //大圖標
.build();
//發送通知:
//第一個參數:是通知的Id,可用此id進行手動關閉
notificationManager.notify(AppConstant.NotificationId_Goto_NotifationActivity, notification);
}
});
//發送通知:Chat
Button btn_send_notification_chat = findViewById(R.id.btn_send_notification_chat);
btn_send_notification_chat.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(MainActivity.this, AppConstant.ChannelId_Chat)
.setContentTitle("收到一條聊天消息")
.setContentText("今天中午吃什么?")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.notif_ico_round) //小圖標
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.notif_ico)) //大圖標
.setAutoCancel(true) //設置點擊通知后自動刪除通知
.build();
manager.notify(AppConstant.NotificationId_Chat, notification);
}
});
//發送通知:Subcribe
Button btn_send_notification_subcribe = findViewById(R.id.btn_send_notification_subcribe);
btn_send_notification_subcribe.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(MainActivity.this, AppConstant.ChannelId_Subcribe)
.setContentTitle("收到一條訂閱消息")
.setContentText("地鐵沿線30萬商鋪搶購中!")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.notif_ico_round) //小圖標
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.notif_ico)) //大圖標
.setAutoCancel(true) //設置點擊通知后自動刪除通知
.build();
manager.notify(AppConstant.NotificationId_Subcribe, notification);
}
});
}
/**
* 因為低版本的手機系統並沒有通知渠道這個功能,不做系統版本檢查的話會在低版本手機上造成崩潰。
* */
private void initNotificationChannel() {
// targetSdkVersion >=26
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String channelName = "聊天消息";
int importance = NotificationManager.IMPORTANCE_HIGH;
createNotificationChannel(AppConstant.ChannelId_Chat, channelName, importance);
channelName = "訂閱消息";
importance = NotificationManager.IMPORTANCE_DEFAULT;
createNotificationChannel(AppConstant.ChannelId_Subcribe, channelName, importance);
}
}
/**
* 創建 NotificationChannel
* */
@TargetApi(Build.VERSION_CODES.O)
private void createNotificationChannel(String channelId, String channelName, int importance) {
/*-------------------------------------------------------------------
創建一個通知渠道至少需要渠道ID、渠道名稱以及重要等級這三個參數,
其中
渠道ID: 可以隨便定義,只要保證全局唯一性就可以。
渠道名稱:是給用戶看的,需要能夠表達清楚這個渠道的用途。
重要等級:重要等級的不同則會決定通知的不同行為,當然這里只是初始狀態下的重要等級,
用戶可以隨時手動更改某個渠道的重要等級,App是無法干預的
*/
NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
}
}
運行效果解析:
-
創建渠道后,App的信息->通知管理->通知類別 欄 多出2個類別:
【聊天信息】、【訂閱消息】
-
通知欄效果:
分別點擊【發送渠道通知:訂閱類別】、【發送渠道通知:聊天類別】
-
通知
重要程度
不同,表現的行為也會不同,
【緊急】級別的通知是允許在屏幕上彈出通知,
現在在手機中開啟這個軟件的:“懸浮通知(允許在屏幕上彈出通知)”權限,-
點擊【發送渠道通知:聊天類別】:有一個懸浮彈框,因為重要程度是:
NotificationManager.IMPORTANCE_HIGH
-
點擊【發送渠道通知:訂閱類別】:是沒有懸浮彈框,因為的重要程度是:
NotificationManager.IMPORTANCE_DEFAULT
-
4.點擊通知跳轉
點擊通知跳轉的另一個活動,創建一個新的活動:NotifationAtivity
:
activity_notifation_ativity.xml
:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="這里是通知跳轉界面"/>
</LinearLayout>
NotifationAtivity.java
:
public class NotifationAtivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notifation_ativity);
Intent intent = getIntent();
String extData_notifi_xiao_v26 = intent.getStringExtra("extData_notifi_xiao-v26");
Log.d("extData", "extData: " + extData_notifi_xiao_v26);
if (extData_notifi_xiao_v26!= null && !extData_notifi_xiao_v26.isEmpty()){
Toast.makeText(this, "點擊通知跳轉,額外信息->" + extData_notifi_xiao_v26, Toast.LENGTH_LONG).show();
}
String extData_notifi_Chat = intent.getStringExtra("extData_notifi_Chat");
Log.d("extData", "extData: " + extData_notifi_Chat);
if (extData_notifi_Chat!= null && !extData_notifi_Chat.isEmpty()){
Toast.makeText(this, "點擊通知跳轉,額外信息->" + extData_notifi_Chat, Toast.LENGTH_LONG).show();
}
String extData_notifi_Subcribe = intent.getStringExtra("extData_notifi_Subcribe");
Log.d("extData", "extData: " + extData_notifi_Subcribe);
if (extData_notifi_Subcribe!= null && !extData_notifi_Subcribe.isEmpty()){
Toast.makeText(this, "點擊通知跳轉,額外信息->" + extData_notifi_Subcribe, Toast.LENGTH_LONG).show();
}
}
}
MainActivity.java
:
//發送通知(< Andriod 8.0)
Button btn_send_notification = findViewById(R.id.btn_send_notification);
btn_send_notification.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this);
//點擊通知的響應動作
Intent intent = new Intent(MainActivity.this, NotifationAtivity.class);
intent.putExtra("extData_notifi_xiao-v26", "發送通知(< Andriod 8.0)時的額外信息");
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = builder
.setContentTitle("通知標題")
.setContentText("通知內容")
.setSmallIcon(R.mipmap.ic_launcher) //小圖標
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_round)) //大圖標
.setContentIntent(pendingIntent)//點擊通知的響應動作
.setAutoCancel(true) //設置點擊通知后自動刪除通知
.build();
//發送通知:
//第一個參數:是通知的Id,可用此id進行手動關閉
notificationManager.notify(AppConstant.NotificationId_Goto_NotifationActivity, notification);
}
});
//發送通知:Chat
Button btn_send_notification_chat = findViewById(R.id.btn_send_notification_chat);
btn_send_notification_chat.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//點擊通知的響應動作
Intent intent = new Intent(MainActivity.this, NotifationAtivity.class);
intent.putExtra("extData_notifi_Chat", "送通知:Chat的額外信息");
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(MainActivity.this, AppConstant.ChannelId_Chat)
.setContentTitle("收到一條聊天消息")
.setContentText("今天中午吃什么?")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.notif_ico_round) //小圖標
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.notif_ico)) //大圖標
.setAutoCancel(true) //設置點擊通知后自動刪除通知
.setContentIntent(pendingIntent)//點擊通知的響應動作
.build();
manager.notify(AppConstant.NotificationId_Chat, notification);
}
});
//發送通知:Subcribe
Button btn_send_notification_subcribe = findViewById(R.id.btn_send_notification_subcribe);
btn_send_notification_subcribe.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Intent intent = new Intent(MainActivity.this, NotifationAtivity.class);
intent.putExtra("extData_notifi_Subcribe", "發送通知:Subcribe的額外信息");
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(MainActivity.this, AppConstant.ChannelId_Subcribe)
.setContentTitle("收到一條訂閱消息")
.setContentText("地鐵沿線30萬商鋪搶購中!")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.notif_ico_round) //小圖標
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.notif_ico)) //大圖標
.setAutoCancel(true) //設置點擊通知后自動刪除通知
.setContentIntent(pendingIntent)//點擊通知的響應動作
.build();
manager.notify(AppConstant.NotificationId_Subcribe, notification);
}
});
要點解析:
-
(1) 創建Intent,並且可以使用
putExtxxx
系列參數傳輸一下額外的數據; -
(2)創建
PendingIntent
,使用創建PendingIntent
的3中方法,
getActivity()
、getBroadcast()
、getService()
根據需求選取,這里使用方法
PendingIntent.getActivit()
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT );
特別注意:第4個參數有4種值:
- int FLAG_CANCEL_CURRENT
:如果該PendingIntent
已經存在,則在生成新的之前取消當前的;
- int FLAG_NO_CREATE
:如果該PendingIntent
不存在,直接返回null而不是創建一個PendingIntent
;
- int FLAG_ONE_SHOT
:該PendingIntent
只能用一次,在send()
方法執行后,自動取消。
- int FLAG_UPDATE_CURRENT
:如果該PendingIntent
已經存在,則用新傳入的Intent更新當前的數據。
我們需要把最后一個參數改為PendingIntent.FLAG_UPDATE_CURRENT
,這樣在啟動的Activity
里就可以用接收Intent傳送數據的方法正常接收。
-(3)通過 Builder.setContentIntent(pendingIntent)....
設置點擊通知的響應動作
-(4)NotifationAtivity
中獲取傳遞的參數:
```
Intent intent = getIntent();
String extData_notifi_xiao_v26 = intent.getStringExtra("extData_notifi_xiao-v26");
```
特別提醒:
各個類別的 通知或通知渠道,跳轉響應的是同一個Activity,這時通過
Intent intent = getIntent();
獲取的Intent 是最后一個通知或通知渠道的Intent,會使得早先的通知的Intent丟失
故,如果通知跳轉,對傳的參數有要求,最好獨立有自己的響應Activity。
5.通知的一些高級設置
5.1在Builder的一系列方法中進行高級設置
Notification notification = new NotificationCompat.Builder(MainActivity.this, AppConstant.ChannelId_Chat)
.setXXX() //這里的一系列方法中進行高級設置
.build();
build.setXXX()一系列方法有:
-
聲音
build..setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg")))
-
振動
build.setVibrate(new long[]{0, 1000,2000, 3000 }) //振動,頻率:靜止,振動1秒,靜止2秒,振動3秒 /*得添加權限:android.permission.VIBRATE*/
振動得聲明振動權限
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.notifationdemo"> <uses-permission android:name="android.permission.VIBRATE"/>
-
亮燈
build..setLights(Color.RED, 1000, 3000) /*亮1秒, 暗3秒*/
-
富文本
富文本內容將替換:
.setContentText("今天中午吃什么?")
設置的內容,但是懸浮彈框中的文字還是顯示的是.setContentText("今天中午吃什么?")
設置的內容,見下圖:

查看消息,顯示的是setStyle()
設置的文本:

(1) 設置長文字:
build.setStyle(new NotificationCompat.BigTextStyle().bigText("這是一個很長很長的文本,我要全部顯示,而不要默認截斷!" +
"這是一個很長很長的文本,我要全部顯示,而不要默認截斷!" +
"這是一個很長很長的文本,我要全部顯示,而不要默認截斷!" +
"這是一個很長很長的文本,我要全部顯示,而不要默認截斷!" +
"這是一個很長很長的文本,我要全部顯示,而不要默認截斷!" +
"這是一個很長很長的文本,我要全部顯示,而不要默認截斷!"))
(2) 設置圖片:
```java
build..setStyle(new NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(getResources(), R.drawable.notif_ico_round)))
```
-
優先級
build.setPriority(NotificationCompat.PRIORITY_MAX) //設置優先級
5.2 為什么聲音、振動、亮燈不起作用
NotificationChannel 適配填坑指南:https://www.jianshu.com/p/99bc32cd8ad6
build.setXXX 系列的設置的聲音、振動、亮燈不起作用
要使用 NotificationChannel 設置 聲音、振動、亮燈
上一節:5.1 , 在【聊天消息】通知渠道 中, 使用 NotificationCompat.Builder.setXXX()
系列中設置 聲音、振動、亮燈 沒有起作用
現使用【訂閱消息】通知渠道 做實驗,看看使用 NotificationChannel
設置通知的 設置 聲音、振動、亮燈 是否起作用
- 重新寫一個方法用於創建【訂閱消息】通知渠道
@RequiresApi(api = Build.VERSION_CODES.O)
private void initNotificationChannelForSubcribe(){
String channelName = "訂閱消息";
String description = "訂閱消息,接收一些日常剛興趣的資訊!!!";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(AppConstant.ChannelId_Subcribe, channelName, importance);
channel.enableVibration(true);
channel.setVibrationPattern(new long[]{0, 1000,2000, 3000, 5000, 2000,2000,1000 } );
channel.enableLights(true);
channel.setLightColor(Color.GREEN);
//channelSubcribe.setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg")); //通知聲音
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
}
...
//發送通知:Subcribe
Button btn_send_notification_subcribe = findViewById(R.id.btn_send_notification_subcribe);
btn_send_notification_subcribe.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Intent intent = new Intent(MainActivity.this, NotifationAtivity.class);
intent.putExtra("extData_notifi_Subcribe", "發送通知:Subcribe的額外信息");
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(MainActivity.this, AppConstant.ChannelId_Subcribe)
.setContentTitle("收到一條訂閱消息")
.setContentText("地鐵沿線30萬商鋪搶購中!")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.notif_ico_round) //小圖標
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.notif_ico)) //大圖標
.setAutoCancel(true) //設置點擊通知后自動刪除通知
.setContentIntent(pendingIntent)//點擊通知的響應動作
.build();
manager.notify(AppConstant.NotificationId_Subcribe, notification);
}
});
-
結果還是沒起作用,原因不明,暫留個記錄
build.gradle
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.example.notifationdemo"
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
測試真機:小米6,Android版本:9
6.關閉通知
- 方法一:
build.setAutoCancel(true) //設置點擊通知后自動刪除通知
- 方法二:
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.cancel(通知Id);//int類型
7.填坑指南
使用示例:https://blog.csdn.net/yxncl/article/details/72801230
Android Support Library詳細介紹:https://www.cnblogs.com/Jeely/p/11043703.html
什么是AndroidX?https://blog.csdn.net/guolin_blog/article/details/97142065
支持庫:https://developer.android.google.cn/topic/libraries/support-library
NotificationChannel 適配填坑指南:https://www.jianshu.com/p/99bc32cd8ad6
通知版本適應:https://www.jianshu.com/p/a5040cc7a693