Android?Notification使用教程詳解
前言
在應(yīng)用的開發(fā)中,我們必然會接觸到應(yīng)用通知這個知識,而在通知是隨著Android版本進(jìn)行不斷變化,為了能在高版本和低版本中使用,就需要開發(fā)者去做適配,也屬于查漏補(bǔ)缺。了解之前,先看一個效果圖吧。

正文
通知的使用的內(nèi)容還是比較多的,此篇文章將會盡可能詳細(xì)的介紹Notification的內(nèi)容。
一、Android中通知的變化
1. Android 4.1,API 16
- 推出了展開式通知模板(稱為通知樣式),可以提供較大的通知內(nèi)容區(qū)域來顯示信息。
- 用戶可以通過單指向上/向下滑動的手勢來展開通知。還支持以按鈕的形式向通知添加其他操作。
- 允許用戶在設(shè)置中按應(yīng)用關(guān)閉通知。
2. Android 4.4,API 19 和 20
- 向 API 中添加了通知監(jiān)聽器服務(wù)。
- API 級別 20 中新增了 Android Wear(現(xiàn)已更名為 Wear OS)支持。
3. Android 5.0,API 21
- 推出了鎖定屏幕和提醒式通知。
- 用戶現(xiàn)在可以將手機(jī)設(shè)為勿擾模式,并配置允許哪些通知在設(shè)備處于“僅限優(yōu)先事項(xiàng)”模式時打擾他們。
- 向 API 集添加了通知是否在鎖定屏幕上顯示的方法 (setVisibility()),以及指定通知文本的“公開”版本的方法。
- 添加了 setPriority() 方法,告知系統(tǒng)通知的“干擾性”(例如,將其設(shè)為“高”可使通知以提醒式通知的形式顯示)。
- 向 Android Wear(現(xiàn)已更名為 Wear OS)設(shè)備添加了通知堆棧支持。使用 setGroup() 將通知放入堆棧。請注意,平板電腦和手機(jī)尚不支持通知堆棧。通知堆棧以后會稱為組或 Bundle。
4. Android 7.0,API 24
- 重新設(shè)置了通知模板的樣式以強(qiáng)調(diào)主打圖片和頭像。
- 添加了三個通知模板:一個用于短信應(yīng)用,另外兩個用于借助展開式選項(xiàng)和其他系統(tǒng)裝飾來裝飾自定義內(nèi)容視圖。
- 向手持設(shè)備(手機(jī)和平板電腦)添加了對通知組的支持。使用與 Android 5.0(API 級別 21)中推出的 Android Wear(現(xiàn)已更名為 Wear OS)通知堆棧相同的 API。
- 用戶可以使用內(nèi)嵌回復(fù)功能直接在通知內(nèi)進(jìn)行回復(fù)(他們輸入的文本將轉(zhuǎn)發(fā)到通知的父應(yīng)用)。
5. Android 8.0,API 26
- 必須將各個通知放入特定渠道中。
- 用戶可以按渠道關(guān)閉通知,而非關(guān)閉來自某個應(yīng)用的所有通知。
- 包含有效通知的應(yīng)用將在主屏幕/啟動器屏幕上相應(yīng)應(yīng)用圖標(biāo)的上方顯示通知“標(biāo)志”。
- 用戶可以從抽屜式通知欄中暫停某個通知。您可以為通知設(shè)置自動超時時間。
- 您還可以設(shè)置通知的背景顏色。
- 部分與通知行為相關(guān)的 API 已從 Notification 移至 NotificationChannel。例如,在搭載 Android 8.0 及更高版本的設(shè)備中,使用 NotificationChannel.setImportance(),而非 NotificationCompat.Builder.setPriority()。
6. Android 12.0,API 31
- 自定義通知,提供通知模板。
- 更改了完全自定義通知的外觀和行為。
下面就開始我們的適配之旅吧。
二、創(chuàng)建項(xiàng)目
新建一個名為NotificationStudy的項(xiàng)目,如下圖所示:

點(diǎn)擊Finish完成項(xiàng)目創(chuàng)建,然后在app的build.gradle中的android{}閉包中開啟viewBinding,代碼如下:
buildFeatures {
viewBinding true
}項(xiàng)目創(chuàng)建好之后,我們首先改動一下activity_main.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/btn_show"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="顯示通知"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
放一個按鈕,然后再修改一下MainActivity中的代碼,如下所示:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
//顯示通知
binding.btnShow.setOnClickListener {
}
}
}這里就是綁定ViewBinding,然后設(shè)置按鈕點(diǎn)擊監(jiān)聽,下面我們就要開始做顯示通知的操作了。
三、顯示通知
常規(guī)的通知由三個內(nèi)容構(gòu)成:標(biāo)題、內(nèi)容和圖標(biāo)。在8.0中還有一個通知渠道,所以我們需要先創(chuàng)建一個通知渠道。
① 創(chuàng)建通知渠道
創(chuàng)建通知渠道需要三個參數(shù),渠道ID、渠道名稱和渠道重要性。
首先在MainActivity中增加幾個變量。
//渠道Id
private val channelId = "test"
//渠道名
private val channelName = "測試通知"
//渠道重要級
private val importance = NotificationManagerCompat.IMPORTANCE_HIGH
//通知管理者
private lateinit var notificationManager: NotificationManager
//通知
private lateinit var notification: Notification
//通知Id
private val notificationId = 1
發(fā)送通知首先要通過通知服務(wù)得到通知管理者,在onCreate方法中增加如下代碼:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
//獲取系統(tǒng)通知服務(wù)
notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
...
}
}
然后是創(chuàng)建通知渠道,在MainActivity中新增如下函數(shù)。
/**
* 創(chuàng)建通知渠道
*/
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(channelId: String, channelName: String, importance: Int) =
notificationManager.createNotificationChannel(NotificationChannel(channelId, channelName, importance))因?yàn)橥ㄖ朗茿ndroid8.0才有的,因此我們添加一個注解,然后將數(shù)據(jù)構(gòu)建通知渠道的參數(shù)傳入進(jìn)來,注意我們通過notificationManager的createNotificationChannel()函數(shù)去創(chuàng)建渠道的,如果notificationManager沒有初始化的話,毫無疑問你的這一行代碼會報錯。
② 初始化通知
通知渠道創(chuàng)建好了,下面我們?nèi)コ跏蓟ㄖ?,同樣在MainActivity中新增一個initNotification()函數(shù),代碼如下:
/**
* 初始化通知
*/
private fun initNotification() {
notification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//創(chuàng)建通知渠道
createNotificationChannel(channelId,channelName,importance)
NotificationCompat.Builder(this, channelId)
} else {
NotificationCompat.Builder(this)
}.apply {
setSmallIcon(R.mipmap.ic_launcher)//小圖標(biāo)(顯示在狀態(tài)欄)
setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))//大圖標(biāo)(顯示在通知上)
setContentTitle("打工人")//標(biāo)題
setContentText("我要搞錢?。?!")//內(nèi)容
}.build()
}
這里首先通過版本判斷檢查是否需要創(chuàng)建通知渠道,然后會得到一個通知的Builder,通過Builder去配置通知所需要的基本參數(shù),這里我設(shè)置了圖標(biāo),標(biāo)題,內(nèi)容,配置完之后調(diào)用build(),完成通知的構(gòu)建,最后返回一個notification,現(xiàn)在我們的通知就構(gòu)建好了。
③ 顯示通知
然后我們再修改一下onCreate中的代碼,如下所示
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
//獲取系統(tǒng)通知服務(wù)
notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
//初始化通知
initNotification()
//顯示通知
binding.btnShow.setOnClickListener {
notificationManager.notify(notificationId, notification)
}
}
這里我們調(diào)用了initNotification()函數(shù),然后在點(diǎn)擊按鈕時發(fā)送通知。
binding.btnShow.setOnClickListener {
notificationManager.notify(notificationId, notification)
}
運(yùn)行一下,效果如下圖所示:

四、通知點(diǎn)擊
在上面的gif中,我們成功顯示了通知,其中我們嘗試去做了點(diǎn)擊通知的動作,但是沒有什么反應(yīng),因?yàn)檫@方面的功能還沒有寫,下面我們就來寫。
首先要想一下點(diǎn)擊之后要干嘛?通常來說都是跳轉(zhuǎn)到指定的Activity,我們當(dāng)前只有一個MainActivity,因此我們需要創(chuàng)建一個。
① 創(chuàng)建目的Activity
我們在com.llw.notification下創(chuàng)建DetailsActivity,對應(yīng)activity_details.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DetailsActivity">
<TextView
android:id="@+id/tv_notification_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
這里增加一個TextView,然后回到DetailsActivity中,修改代碼如下:
class DetailsActivity : AppCompatActivity() {
private lateinit var binding: ActivityDetailsBinding
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDetailsBinding.inflate(layoutInflater)
setContentView(binding.root)
intent?.let {
binding.tvNotificationContent.text =
"${it.getStringExtra("title")}\n" + "${it.getStringExtra("content")}"
}
}
}這里的代碼也很簡單,就是獲取傳遞過來的intent中攜帶的參數(shù)顯示在TextView上,假設(shè)我們在MainActivity中點(diǎn)擊時傳遞title和content。
② PendingIntent使用
我們經(jīng)常使用Intent,但是接觸PendingIntent是比較少的,PendingIntent可以看作是對Intent的一個封裝,但它不是立刻執(zhí)行某個行為,而是滿足某些條件或觸發(fā)某些事件后才執(zhí)行指定的行為。
PendingIntent獲取有三種方式:Activity、Service和BroadcastReceiver獲取。PendingIntent有一個比較簡單的使用方式,例如我們現(xiàn)在要在Activity中使用,修改initNotification()函數(shù)中的代碼:
private fun initNotification() {
val title = "打工人"
val content = "我要搞錢!??!"
// 為DetailsActivity 創(chuàng)建顯式 Intent
val intent = Intent(this, DetailsActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
putExtra("title", title).putExtra("content", content)
}
val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
notification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//創(chuàng)建通知渠道
createNotificationChannel(channelId, channelName, importance)
NotificationCompat.Builder(this, channelId)
} else {
NotificationCompat.Builder(this)
}.apply {
setSmallIcon(R.mipmap.ic_launcher)//小圖標(biāo)(顯示在狀態(tài)欄)
setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))//大圖標(biāo)(顯示在通知上)
setContentTitle(title)//標(biāo)題
setContentText(content)//內(nèi)容
setContentIntent(pendingIntent)//設(shè)置內(nèi)容意圖
}.build()
}這里的代碼解釋一下,首先將title、content抽離出來,然后創(chuàng)建intent,再創(chuàng)建pendingIntent 。最后在配置build中設(shè)置setContentIntent(pendingIntent),下面我們運(yùn)行一下。

這里已經(jīng)完成了點(diǎn)擊通知并傳遞的操作,這里還有一個細(xì)節(jié)就是常規(guī)來說我們點(diǎn)擊了這個通知表示我們已經(jīng)看到了,或者已經(jīng)知曉了內(nèi)容,因此通知就會消失,而這里通知并沒有消息。
只需要一個配置就可以做到。
setAutoCancel(true)//設(shè)置自動取消
添加位置如下圖所示:

運(yùn)行測試一下就行,我就不用gif說明了。
五、折疊通知
有時候我們設(shè)置通知的內(nèi)容可能一行放不下,這個時候就需要收縮和展開通知,讓用戶看到完整的信息。
① 長文本
現(xiàn)在我將content的內(nèi)容修改一下:
val content = "我要搞錢!??!富強(qiáng)、明主、文明、和諧、自由、平等、公正、法治、愛國、敬業(yè)、誠信、友善"
然后我們什么都不做去運(yùn)行看看。

這里并沒有顯示多行,同時也沒有那個向下展開的按鈕,內(nèi)容文字做了省略,因此這說明那個展開需要我們?nèi)ピO(shè)置。
一行代碼搞定:
setStyle(NotificationCompat.BigTextStyle().bigText(content))
通過設(shè)置通知的風(fēng)格樣式,這里使用的是長文本信息樣式,將content傳遞進(jìn)去。添加位置如下圖所示:

運(yùn)行一下看看

② 顯示圖片
有時候我們會在通知中展開時看到圖片,實(shí)際上就是使用了另一個樣式,也是一行代碼解決。
setStyle(NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(resources,R.drawable.logo)))//設(shè)置樣式
這行代碼的位置和替換掉剛才哪一行,通知只能設(shè)置一個樣式,后面設(shè)置的樣式會覆蓋掉前面的樣式,這里我們使用大圖片樣式,傳進(jìn)入一個logo.jpg圖片,你在寫的時候隨便用什么都行,然后我們再運(yùn)行一下。

六、回復(fù)通知
有時候我們的手機(jī)收到短信消息,是可以直接回復(fù)的。當(dāng)然了這個功能是需要手動去寫的。流程就是點(diǎn)擊按鈕出現(xiàn)一個通知,通知中回復(fù)消息,廣播或服務(wù)收到消息后更新通知,然后關(guān)閉通知。
① 創(chuàng)建廣播
這里我們先來寫這個接收回復(fù)消息的處理,這里用廣播來處理,首先我們需要創(chuàng)建一個廣播,在com.llw.notification下新建一個ReplyMessageReceiver類,里面的代碼如下:
class ReplyMessageReceiver : BroadcastReceiver() {
private val TAG = ReplyMessageReceiver::class.java.simpleName
override fun onReceive(context: Context, intent: Intent) {
//獲取回復(fù)消息的內(nèi)容
val inputContent =
RemoteInput.getResultsFromIntent(intent)?.getCharSequence("key_text_reply")?.toString()
Log.d(TAG, "onReceive: $inputContent")
if (inputContent == null) {
Log.e(TAG, "onReceive: 沒有回復(fù)消息!")
return
}
//構(gòu)建回復(fù)消息通知
val repliedNotification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationCompat.Builder(context, "reply")
} else {
NotificationCompat.Builder(context)
}.apply {
setSmallIcon(R.mipmap.ic_launcher)//小圖標(biāo)(顯示在狀態(tài)欄)
setContentTitle("1008666")//標(biāo)題
setContentText("消息發(fā)送成功!")//內(nèi)容
}.build()
val notificationManager =
context.getSystemService(AppCompatActivity.NOTIFICATION_SERVICE) as NotificationManager
//發(fā)送通知
notificationManager.notify(2, repliedNotification)
//1秒后取消通知
Timer().schedule(1000){
notificationManager.cancel(2)
}
}
}
這里說明一下:首先是RemoteInput表示遠(yuǎn)程輸入,也就是通知欄上輸入框,這里就是獲取輸入框的內(nèi)容,注意"key_text_reply"這個值,我們在構(gòu)建RemoteInput時使用的值要與這個一致,不一致你在廣播中就拿不到輸入的值。
然后是構(gòu)建通知了,這里的設(shè)置都是常規(guī)操作,渠道id我是寫死的,因此在Activity中創(chuàng)建通知時渠道Id也要一致。最后就是在發(fā)送通知之后加了一個1秒的延時去取消通知,表示收到回復(fù)的處理。
廣播是需要在AndroidManifest.xml注冊的,代碼如下:
<receiver android:name=".ReplyMessageReceiver"/>
位置如下:

下面就是要構(gòu)建回復(fù)通知了。因?yàn)橐獏^(qū)別于之前的普通通知,所以這里我需要更改一下activity_main.xml中的布局代碼
<Button
android:id="@+id/btn_show_reply"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="顯示回復(fù)通知"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_show" />
增加一個按鈕,點(diǎn)擊事件后面再寫。
② RemoteInput
為了區(qū)分普通通知和回復(fù)通知,在MainActivity中定義一下。
//回復(fù)通知Id
private val replyNotificationId = 2
//回復(fù)通知
private lateinit var replyNotification: Notification
下面我們新建一個initReplyNotification()函數(shù),在里面對RemoteInput進(jìn)行構(gòu)建。
private fun initReplyNotification() {
//遠(yuǎn)程輸入
val remoteInput = RemoteInput.Builder("key_text_reply").setLabel("快速回復(fù)").build()
}
這里RemoteInput的構(gòu)建也很簡單,最關(guān)鍵的就是"key_text_reply",剛才在適配器中已經(jīng)說了,而Label就是一個輸入框的提示文本。
③ PendingIntent
現(xiàn)在我們要通過BroadcastReceiver獲取PendingIntent,在initReplyNotification()函數(shù)中新增代碼:
private fun initReplyNotification() {
...
//構(gòu)建回復(fù)pendingIntent
val replyIntent = Intent(this, ReplyMessageReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 0, replyIntent, PendingIntent.FLAG_ONE_SHOT)
}
④ NotificationCompat.Action
通知動作,我們在輸入框?qū)懭胄畔?,需要一個按鈕發(fā)送這個按鈕,這個Action就是用來做這個事情的,在initReplyNotification()函數(shù)中新增代碼:
private fun initReplyNotification() {
...
//構(gòu)建回復(fù)pendingIntent
val replyIntent = Intent(this, ReplyMessageReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 0, replyIntent, PendingIntent.FLAG_ONE_SHOT)
}
⑤ 構(gòu)建通知
下面就是構(gòu)建通知,在initReplyNotification()函數(shù)中新增代碼:
private fun initReplyNotification() {
...
//構(gòu)建通知
replyNotification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel("reply", "回復(fù)消息", importance)
NotificationCompat.Builder(this, "reply")
} else {
NotificationCompat.Builder(this)
}.apply {
setSmallIcon(R.mipmap.ic_launcher)//小圖標(biāo)(顯示在狀態(tài)欄)
setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))//大圖標(biāo)(顯示在通知上)
setContentTitle("1008666")//標(biāo)題
setContentText("你的賬號已欠費(fèi)2000元!")//內(nèi)容
addAction(action)
}.build()
}
這里的關(guān)鍵就在于這個addAction(action),下面我們運(yùn)行一下:

然后我們看看日志:

七、橫幅通知
橫幅通知我相信你一定見過,例如收到短信、QQ、微信、釘釘?shù)南?,都會有出現(xiàn)在屏幕頂部,主要是用于提醒用戶的。
首先我們修改布局,在activity_main.xml中新增一個按鈕,代碼如下:
<Button
android:id="@+id/btn_show_banner"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="顯示橫幅通知"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_show_reply" />
① 檢查橫幅通知是否打開
首先在MainActivity中定義幾個變量
//橫幅通知
private lateinit var bannerNotification: Notification
//橫幅通知Id
private val bannerNotificationId = 3
//開啟橫幅通知返回
private val bannerLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
Log.d("TAG", "返回結(jié)果")
}
}
然后新增一個openBannerNotification()函數(shù),代碼如下:
private fun openBannerNotification() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val bannerImportance = notificationManager.getNotificationChannel("banner").importance
if (bannerImportance == NotificationManager.IMPORTANCE_DEFAULT) {
val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
.putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
.putExtra(Settings.EXTRA_CHANNEL_ID, "banner")
bannerLauncher.launch(intent); false
} else true
} else true
這里通過檢查通知遇到的重要級判斷是否開啟橫幅通知。
② 構(gòu)建橫幅通知渠道
在MainActivity中新增createBannerNotificationChannel()函數(shù),代碼如下:
@RequiresApi(Build.VERSION_CODES.O)
private fun createBannerNotificationChannel(channelId: String, channelName: String, importance: Int) =
notificationManager.createNotificationChannel(
NotificationChannel(channelId, channelName, importance).apply {
description = "提醒式通知"http://渠道描述
enableLights(true)//開啟閃光燈
lightColor = Color.BLUE//設(shè)置閃光燈顏色
enableVibration(true)//開啟震動
vibrationPattern = longArrayOf(0, 1000, 500, 1000)//震動模式
setSound(null, null)//沒有提示音
}
)
這里的內(nèi)容相對于之前來說就多一些,有注釋也好理解。
③ 構(gòu)建橫幅通知
在MainActivity中新增initBannerNotification()函數(shù),代碼如下:
private fun initBannerNotification() {
//構(gòu)建通知
bannerNotification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createBannerNotificationChannel("banner", "提醒消息", importance)
NotificationCompat.Builder(this, "banner")
} else {
NotificationCompat.Builder(this)
}.apply {
setSmallIcon(R.mipmap.ic_launcher)//小圖標(biāo)(顯示在狀態(tài)欄)
setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))//大圖標(biāo)(顯示在通知上)
setContentTitle("落魄Android在線炒粉")//標(biāo)題
setContentText("不要9塊9,不要6塊9,只要3塊9。")//內(nèi)容
setWhen(System.currentTimeMillis())//通知顯示時間
setAutoCancel(true)//設(shè)置自動取消
}.build()
}
這里也就是一些常規(guī)的設(shè)置。
④ 顯示橫幅通知
最后我們在onCreate()函數(shù)中,新增如下代碼:
//顯示橫幅通知
binding.btnShowBanner.setOnClickListener {
//檢查是否授予訪問權(quán)限
if (openBannerNotification()) {
notificationManager.notify(bannerNotificationId, bannerNotification)
}
}
下面我們運(yùn)行一下:

OK,這樣就可以了。
八、常駐通知
我們知道有一些通知,當(dāng)程序運(yùn)行的時候就會出現(xiàn),例如我們最常見的音樂類App,而且這個通知并不是馬上出現(xiàn)的,在此之前還有很多內(nèi)容要初始化,一切就緒之后出現(xiàn)這個通知,就可以通過通知去控制音樂了。

我們并不需要這種復(fù)雜的操作,只有有一個通知能在App啟動的時候顯示出來,并且App進(jìn)入后臺時,通知也還在。
在MainActivity創(chuàng)建變量。
//常駐通知
private lateinit var permanentNotification:
//常駐通知Id
private val permanentNotificationId = 4Notification然后在MainActivity中新增一個showPermanentNotification()函數(shù),代碼如下:
private fun showPermanentNotification() {
//構(gòu)建回復(fù)pendingIntent
val permanentIntent = Intent(this, MainActivity::class.java)
val pendingIntent =
PendingIntent.getActivity(this, 0, permanentIntent, PendingIntent.FLAG_UPDATE_CURRENT)
//構(gòu)建通知
permanentNotification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel("permanent", "我一直存在", importance)
NotificationCompat.Builder(this, "permanent")
} else {
NotificationCompat.Builder(this)
}.apply {
setSmallIcon(R.mipmap.ic_launcher)//小圖標(biāo)(顯示在狀態(tài)欄)
setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))//大圖標(biāo)(顯示在通知上)
setContentTitle("你在努力些什么?")//標(biāo)題
setContentText("搞錢!搞錢!還是搞錢!")//內(nèi)容
setWhen(System.currentTimeMillis())//通知顯示時間
setContentIntent(pendingIntent)
}.build()
permanentNotification.flags = Notification.FLAG_ONGOING_EVENT
notificationManager.notify(permanentNotificationId, permanentNotification)
}
這里就很簡單了,主要就是去掉通知取消設(shè)置,同時設(shè)置FLAG_ONGOING_EVENT,另外在點(diǎn)擊通知的時候進(jìn)入主頁面。在onCreate()函數(shù)中調(diào)用。

運(yùn)行一下:

可以看到這里我用別的通知顯示出來之后,清理一下,其他通知就沒有了,而常駐通知還在,然后我程序進(jìn)入后臺,點(diǎn)擊常駐通知,又會啟動到前臺。
九、自定義樣式通知
現(xiàn)在我們使用的都是常規(guī)的樣式通知,實(shí)際上我們可以自定義的,就是自定義通知布局,我們先來設(shè)計自定義布局的樣式,就做一個音樂通知欄吧,首先是三個圖標(biāo)。
① 自定義通知布局
在drawable文件夾下新建ic_previous.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="36dp"
android:height="36dp"
android:tint="@color/white"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="@android:color/white"
android:pathData="M7,6c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L6,7c0,-0.55 0.45,-1 1,-1zM10.66,12.82l5.77,4.07c0.66,0.47 1.58,-0.01 1.58,-0.82L18.01,7.93c0,-0.81 -0.91,-1.28 -1.58,-0.82l-5.77,4.07c-0.57,0.4 -0.57,1.24 0,1.64z" />
</vector>
ic_play.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="36dp"
android:height="36dp"
android:tint="@color/white"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="@android:color/white"
android:pathData="M8,6.82v10.36c0,0.79 0.87,1.27 1.54,0.84l8.14,-5.18c0.62,-0.39 0.62,-1.29 0,-1.69L9.54,5.98C8.87,5.55 8,6.03 8,6.82z" />
</vector>
ic_next.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="36dp"
android:height="36dp"
android:tint="@color/white"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="@android:color/white"
android:pathData="M7.58,16.89l5.77,-4.07c0.56,-0.4 0.56,-1.24 0,-1.63L7.58,7.11C6.91,6.65 6,7.12 6,7.93v8.14c0,0.81 0.91,1.28 1.58,0.82zM16,7v10c0,0.55 0.45,1 1,1s1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1z" />
</vector>
然后在layout下新建一個layout_custom_notification.xml,代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/black"
android:gravity="center_vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_song_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="雨下一整晚"
android:textColor="@color/white"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_singer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:text="周杰倫"
android:textColor="@color/white"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
<ImageButton
android:id="@+id/iv_previous"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:src="@drawable/ic_previous" />
<ImageButton
android:id="@+id/iv_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:background="@null"
android:src="@drawable/ic_play" />
<ImageButton
android:id="@+id/iv_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:src="@drawable/ic_next" />
</LinearLayout>
<ImageView
android:id="@+id/iv_avatar"
android:layout_width="72dp"
android:layout_height="72dp"
android:src="@drawable/jay" />
</LinearLayout>
這里要注意一點(diǎn)自定義通知的界面布局只支持LinearLayout、RelativeLayout、FrameLayout,目前不支持ConstraintLayout通知布局里有ConstraintLayout的話,彈通知不會顯示。
jpg圖標(biāo)用自己的,或者用我源碼里面都可以,然后就很簡單了,回到MainActivity。
② 顯示自定義通知
//自定義通知
private lateinit var customNotification: Notification
//自定義通知Id
private val customNotificationId = 5
然后創(chuàng)建initCustomNotification()函數(shù),代碼如下:
@SuppressLint("RemoteViewLayout")
private fun initCustomNotification() {
//RemoteView
val remoteViews = RemoteViews(packageName, R.layout.layout_custom_notification)
customNotification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel("custom", "自定義通知", importance)
NotificationCompat.Builder(this, "custom")
} else {
NotificationCompat.Builder(this)
}.apply {
setSmallIcon(R.mipmap.ic_launcher)//小圖標(biāo)(顯示在狀態(tài)欄)
setCustomContentView(remoteViews)//設(shè)置自定義內(nèi)容視圖
setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
setOnlyAlertOnce(true)
setOngoing(true)
}.build()
}
在onCreate中調(diào)用

然后我們在activity_main.xml中新增一個按鈕:
<Button
android:id="@+id/btn_show_custom"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="顯示自定義通知"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_show_banner" />
最后在MainActivity中的onCreate()函數(shù)中新增按鈕點(diǎn)擊事件,同時點(diǎn)擊調(diào)用通知顯示:
//顯示自定義通知
binding.btnShowCustom.setOnClickListener {
notificationManager.notify(customNotificationId, customNotification)
}
運(yùn)行一下:

③ 自定義通知大小
通知布局視圖布局的高度上限為 64 dp,展開后的視圖布局的高度上限為 256 dp,剛才我們只設(shè)置了小的通知,那么如果要展開一個大一點(diǎn)的通知,最好是能夠滑動通知的時候有大小變化。
其實(shí)很簡單,首先我們同樣要定義一個大一點(diǎn)同通知布局,在layout下新建一個layout_custom_notification_big.xml,代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/black"
android:gravity="center_vertical">
<TextView
android:id="@+id/tv_song_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="雨下一整晚"
android:textColor="@color/white"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_singer"
android:layout_below="@+id/tv_song_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="6dp"
android:text="周杰倫"
android:textColor="@color/white"
android:textSize="16sp" />
<LinearLayout
android:layout_marginTop="16dp"
android:layout_below="@+id/tv_singer"
android:layout_alignParentStart="true"
android:layout_toStartOf="@+id/iv_avatar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center">
<ImageButton
android:id="@+id/iv_previous"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:src="@drawable/ic_previous" />
<ImageButton
android:id="@+id/iv_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:background="@null"
android:src="@drawable/ic_play" />
<ImageButton
android:id="@+id/iv_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:src="@drawable/ic_next" />
</LinearLayout>
<ImageView
android:layout_alignParentEnd="true"
android:id="@+id/iv_avatar"
android:layout_width="144dp"
android:layout_height="144dp"
android:src="@drawable/jay" />
</RelativeLayout>
然后我們修改initCustomNotification()函數(shù)中的代碼:
@SuppressLint("RemoteViewLayout")
private fun initCustomNotification() {
//RemoteView
val remoteViews = RemoteViews(packageName, R.layout.layout_custom_notification)
val bigRemoteViews = RemoteViews(packageName, R.layout.layout_custom_notification_big)
customNotification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel("custom", "自定義通知", importance)
NotificationCompat.Builder(this, "custom")
} else {
NotificationCompat.Builder(this)
}.apply {
setSmallIcon(R.mipmap.ic_launcher)//小圖標(biāo)(顯示在狀態(tài)欄)
setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
setCustomContentView(remoteViews)
setCustomBigContentView(bigRemoteViews)
setOnlyAlertOnce(true)
setOngoing(true)
}.build()
}
我們再創(chuàng)建一個RemoteView,然后通過setCustomBigContentView設(shè)置一下就可以了,下面運(yùn)行一下,看看效果。

十、源碼
如果你覺得代碼對你有幫助的話,不妨Fork或者Star一下~
GitHub:NotificationStudy
到此這篇關(guān)于Android Notification使用的文章就介紹到這了,更多相關(guān)Android Notification使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android使用Notification在狀態(tài)欄上顯示通知
- Android編程使用Service實(shí)現(xiàn)Notification定時發(fā)送功能示例
- Android 使用AlarmManager和NotificationManager來實(shí)現(xiàn)鬧鐘和通知欄
- android使用NotificationListenerService監(jiān)聽通知欄消息
- Android種使用Notification實(shí)現(xiàn)通知管理以及自定義通知欄實(shí)例(示例四)
- Android使用Notification實(shí)現(xiàn)普通通知欄(一)
- Android中通知Notification使用實(shí)例(振動、燈光、聲音)
相關(guān)文章
Android解析服務(wù)器端發(fā)來的xml數(shù)據(jù)示例
Android跟服務(wù)器交互數(shù)據(jù),有時數(shù)據(jù)量大時,就需要以xml形式的交互數(shù)據(jù),下面與大家分享下使用XmlPullParser來解析xml數(shù)據(jù),感興趣的朋友可以參考下哈2013-06-06
Android 將本地資源圖片轉(zhuǎn)換成Drawable,進(jìn)行設(shè)置大小操作
這篇文章主要介紹了Android 將本地資源圖片轉(zhuǎn)換成Drawable,進(jìn)行設(shè)置大小操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
Flutter使用sqflite處理數(shù)據(jù)表變更的方法詳解
了解過數(shù)據(jù)庫的同學(xué)應(yīng)該會知道,數(shù)據(jù)表結(jié)構(gòu)是可能發(fā)生改變的。所以本文為大家介紹了Flutter?使用?sqflite?處理數(shù)據(jù)表變更的版本升級處理方法,感興趣的可以了解一下2023-04-04
android 調(diào)用JNI SO動態(tài)庫的方法
android 調(diào)用JNI 分為靜態(tài)調(diào)用與動態(tài)調(diào)用,接下來通過本文給大家介紹android 調(diào)用JNI SO動態(tài)庫的方法,感興趣的朋友一起看看吧2021-11-11
Android使用Service實(shí)現(xiàn)IPC通信的2種方式
這篇文章主要介紹了Android使用Service實(shí)現(xiàn)IPC通信的2種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
React Native開發(fā)中自動打包腳本的實(shí)例代碼
這篇文章主要介紹了React Native開發(fā)中自動打包腳本的實(shí)例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-09-09

