在Android应用开发中我们经常会使用到通知栏的功能,安卓的通知栏有多种类型样式,包括基本类型、带进度条的类型、大图标类型、大段文本类型等,在Android 8.0 (API level 26) 中使用通知栏的代码示例:
// Create an explicit intent for an Activity in your app
val intent = Intent(this, AlertDetails::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
val builder: NotificationCompat.Builder = NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setPriority(NotificationCompat.PRIORITY_DEFAULT) // Set the intent that will fire when the user taps the notification
.setContentIntent(pendingIntent)
.setAutoCancel(true)
val notificationManager = NotificationManagerCompat.from(this)
// notificationId is a unique int for each notification that you must define
notificationManager.notify(notificationId, builder.build())
以下会对notification的使用做一个简单的封装,具体的功能逻辑还可以再扩展
先看一下具体的使用:
package com.let.myapplication
import android.app.PendingIntent
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity(), View.OnClickListener {
private val TAG = MainActivity::class.java.simpleName
var tvImMsg: TextView? = null
var tvSysMsg: TextView? = null
private val userArray = arrayOf("Cyra", "Morgen", "Iris", "Mia")
private val messageArray = arrayOf("我发表了新的美食文章", "我更新了我的相册", "我在FaceBook申请了账号", "我做了一个好看的小视频")
private val sysMessageArray = arrayOf("有新的系统版本可以升级", "收到新的资讯内容", "为你推荐周边美食、娱乐活动", "最新最火爆的游戏")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tvImMsg = findViewById(R.id.textview_im_msg)
tvSysMsg = findViewById(R.id.textview_sys_msg)
tvImMsg!!.setOnClickListener(this)
tvSysMsg!!.setOnClickListener(this)
}
override fun onClick(v: View) {
when (v.id) {
R.id.textview_im_msg -> notifyImMessage()
R.id.textview_sys_msg -> notifySysMessage()
else -> {}
}
}
private fun notifyImMessage() {
val uIndex = (Math.random() * userArray.size).toInt()
val mIndex = (Math.random() * messageArray.size).toInt()
val userName = userArray[uIndex]
val content = messageArray[mIndex]
val key = "ImMessage#$userName"
val requestCode = NotifyManager.getInstance(this@MainActivity).initNotifyId(key)
Log.d(TAG, "method:notifyReceivedMessage#key=$key, requestCode=$requestCode")
val intent = Intent(this@MainActivity, NotificationMsgActivity::class.java)
intent.putExtra("msgContent", "$userName:\n\n$content")
val pendingIntent = PendingIntent.getActivity(this@MainActivity, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val defaultNotifyBuilder = DefaultNotifyBuilder(userName, content)
.setChannelId(resources.getString(R.string.channel_001))
.setContentIntent(pendingIntent)
NotifyManager.getInstance(this@MainActivity).showDefaultNotification(key, defaultNotifyBuilder)
}
private fun notifySysMessage() {
val key = "SysMessage#系统消息"
val mIndex = (Math.random() * sysMessageArray.size).toInt()
val content = sysMessageArray[mIndex]
val requestCode = NotifyManager.getInstance(this@MainActivity).initNotifyId(key)
Log.d(TAG, "method:notifyReceivedMessage#key=$key, requestCode=$requestCode")
val intent = Intent(this@MainActivity, NotificationMsgActivity::class.java)
intent.putExtra("msgContent", "系统消息:\n\n$content")
val pendingIntent = PendingIntent.getActivity(this@MainActivity, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val defaultNotifyBuilder = DefaultNotifyBuilder("系统消息", content)
.setChannelId(resources.getString(R.string.channel_002))
.setContentIntent(pendingIntent)
NotifyManager.getInstance(this@MainActivity).showDefaultNotification(key, defaultNotifyBuilder)
}
}
DefaultNotifyBuilder中有一些参数会有默认值:
package com.let.myapplication
import android.app.PendingIntent
import androidx.core.app.NotificationCompat
/**
* @author let
*/
class DefaultNotifyBuilder {
@JvmField
var channelId: String? = null
@JvmField
var smallIcon = R.drawable.ic_launcher_foreground
@JvmField
var contentTitle: CharSequence = "小蜗牛Tech"
@JvmField
var contentText: CharSequence
@JvmField
var ticker: CharSequence? = null
var flag = NotificationCompat.FLAG_AUTO_CANCEL
@JvmField
var priority = NotificationCompat.PRIORITY_HIGH
@JvmField
var `when` = System.currentTimeMillis()
@JvmField
var contentIntent: PendingIntent? = null
@JvmField
var autoCancel = true
@JvmField
var sound = false
@JvmField
var vibrate = false
@JvmField
var lights = false
constructor(contentText: CharSequence) {
this.contentText = contentText
}
constructor(contentTitle: CharSequence, contentText: CharSequence) {
this.contentTitle = contentTitle
this.contentText = contentText
}
constructor(smallIcon: Int, contentTitle: CharSequence, contentText: CharSequence) {
this.smallIcon = smallIcon
this.contentTitle = contentTitle
this.contentText = contentText
}
fun setChannelId(channelId: String?): DefaultNotifyBuilder {
this.channelId = channelId
return this
}
fun setTicker(ticker: CharSequence?): DefaultNotifyBuilder {
this.ticker = ticker
return this
}
fun setFlag(flag: Int): DefaultNotifyBuilder {
this.flag = flag
return this
}
fun setPriority(priority: Int): DefaultNotifyBuilder {
this.priority = priority
return this
}
fun setWhen(`when`: Long): DefaultNotifyBuilder {
this.`when` = `when`
return this
}
fun setContentIntent(contentIntent: PendingIntent?): DefaultNotifyBuilder {
this.contentIntent = contentIntent
return this
}
fun setAutoCancel(autoCancel: Boolean): DefaultNotifyBuilder {
this.autoCancel = autoCancel
return this
}
fun setSound(sound: Boolean): DefaultNotifyBuilder {
this.sound = sound
return this
}
fun setVibrate(vibrate: Boolean): DefaultNotifyBuilder {
this.vibrate = vibrate
return this
}
fun setLights(lights: Boolean): DefaultNotifyBuilder {
this.lights = lights
return this
}
}
BaseNotifyBuilder会对基本的参数进行组装:
package com.let.myapplication
import android.app.Notification
import android.content.Context
import android.os.Build
import android.text.TextUtils
import android.util.Log
import androidx.core.app.NotificationCompat
import com.let.myapplication.BaseNotifyBuilder
/**
* @author let
*/
open class BaseNotifyBuilder(protected var defaultBuilder: DefaultNotifyBuilder) {
@JvmField
protected var notifyBuilder: NotificationCompat.Builder? = null
open fun build(context: Context?): Notification? {
notifyBuilder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationCompat.Builder(context!!, defaultBuilder.channelId!!)
} else {
NotificationCompat.Builder(context!!)
}
Log.d(TAG, "method:build#defaultBuilder=$defaultBuilder")
// 设置顶部状态栏的小图标
notifyBuilder!!.setSmallIcon(defaultBuilder.smallIcon)
// 设置通知中心的标题
notifyBuilder!!.setContentTitle(defaultBuilder.contentTitle)
// 设置通知中心中的内容
val contentText = defaultBuilder.contentText
if (!TextUtils.isEmpty(contentText)) {
notifyBuilder!!.setContentText(defaultBuilder.contentText)
}
val contentIntent = defaultBuilder.contentIntent
if (contentIntent != null) {
notifyBuilder!!.setContentIntent(contentIntent)
}
var defaults = 0
val sound = defaultBuilder.sound
val vibrate = defaultBuilder.vibrate
val lights = defaultBuilder.lights
if (sound) {
defaults = defaults or Notification.DEFAULT_SOUND
}
if (vibrate) {
defaults = defaults or Notification.DEFAULT_VIBRATE
}
if (lights) {
defaults = defaults or Notification.DEFAULT_LIGHTS
}
if (defaults != 0) {
notifyBuilder!!.setDefaults(defaults)
}
val ticker = defaultBuilder.ticker
if (!TextUtils.isEmpty(ticker)) {
notifyBuilder!!.setTicker(defaultBuilder.ticker)
}
notifyBuilder!!.setAutoCancel(defaultBuilder.autoCancel)
notifyBuilder!!.setWhen(defaultBuilder.`when`)
notifyBuilder!!.priority = defaultBuilder.priority
return notifyBuilder!!.build()
}
companion object {
private val TAG = BaseNotifyBuilder::class.java.simpleName
}
}
MyNotificationManager采用单例模式
从 Android 8.0(API 级别 26)开始,必须为所有通知分配渠道,否则通知将不会显示。通过将通知归类为不同的渠道,用户可以停用您应用的特定通知渠道(而非停用您的所有通知),还可以控制每个渠道的视觉和听觉选项,所有这些操作都在 Android 系统设置中完成。用户还可以长按通知以更改所关联渠道的行为。
package com.let.myapplication
import android.app.NotificationChannel
import android.app.NotificationChannelGroup
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import android.util.Log
import com.let.myapplication.NotifyManager
import java.util.concurrent.atomic.AtomicInteger
/**
* @author let
*
*
* 封装通知栏实现,对于某些相关属性的处理逻辑,可根据具体的需求调整完善
*/
class NotifyManager private constructor() {
/**
* 通知栏的消息对象的自增Id
*/
private val mInitialNotifyId: AtomicInteger? = AtomicInteger(0)
/**
* 全局通知栏的Id,不同消息对象,对应自身唯一的全局Id
*/
@Volatile
private var mGlobalNotifyIdMap: MutableMap<Any, Int>? = null
val initialNotifyId: Int
get() = mInitialNotifyId?.toInt() ?: 0
val globalNotifyIdMap: Map<Any, Int>?
get() = mGlobalNotifyIdMap
/**
* IM消息的key的形式:key = "ImMessage"
*
* @param key
* @return 返回对应的id
*/
fun initNotifyId(key: Any): Int {
Log.d(TAG, "method:initNotifyId#key=$key")
if (mGlobalNotifyIdMap == null) {
mGlobalNotifyIdMap = HashMap()
}
val notifyId = mGlobalNotifyIdMap!![key]
Log.d(TAG, "method:initNotifyId#mGlobalNotifyIdMap=$mGlobalNotifyIdMap")
Log.d(TAG, "method:initNotifyId#notifyId=$notifyId")
return notifyId ?: putNotifyId(key)
}
/**
* 保证每次往集合[.mGlobalNotifyIdMap]中put新值时,ID都是自增的
*
*
* IM消息的key的形式:key = "ImMessage"
*
* @param key
* @return
*/
private fun putNotifyId(key: Any): Int {
Log.d(TAG, "method:putNotifyId#key=$key")
if (mGlobalNotifyIdMap != null) {
val value = mInitialNotifyId!!.incrementAndGet()
Log.d(TAG, "method:putNotifyId#mInitialNotifyId.incrementAndGet#value=$value")
mGlobalNotifyIdMap!![key] = value
Log.d(TAG, "method:putNotifyId#mGlobalNotifyIdMap=$mGlobalNotifyIdMap")
return value
}
return 0
}
private fun notify(key: Any, builder: BaseNotifyBuilder) {
val notifyId = initNotifyId(key)
notificationManager!!.notify(notifyId, builder.build(mContext))
}
val channelGroupList: List<NotificationChannelGroup>?
get() = mChannelGroupList
fun showDefaultNotification(key: Any, defaultBuilder: DefaultNotifyBuilder?) {
val builder = BaseNotifyBuilder(defaultBuilder!!)
notify(key, builder)
}
fun showProgressNotification(key: Any, progress: Int, max: Int, interminate: Boolean, defaultBuilder: DefaultNotifyBuilder?) {
val builder = ProgressNotifyBuilder(defaultBuilder)
notify(key, builder)
}
fun showLargeIconNotification(key: Any, largeIconId: Int, defaultBuilder: DefaultNotifyBuilder?) {
val builder: LargeIconNotifyBuilder = LargeIconNotifyBuilder(defaultBuilder).setLargeIcon(largeIconId)
notify(key, builder)
}
fun showBigTextNotification(key: Any, bigText: String?, defaultBuilder: DefaultNotifyBuilder?) {
val builder = BigTextNotifyBuilder(defaultBuilder).setBigText(bigText)
notify(key, builder)
} // ……………… 根据需要完善其它通知栏样式 ………………
companion object {
private val TAG = NotifyManager::class.java.simpleName
private var sInstance: NotifyManager? = null
var notificationManager: NotificationManager? = null
get() = Companion.field
private set
private var mChannelGroupList: MutableList<NotificationChannelGroup>? = null
private var mContext: Context? = null
fun getInstance(context: Context): NotifyManager? {
if (sInstance == null) {
synchronized(NotifyManager::class.java) {
if (sInstance == null) {
sInstance = NotifyManager()
mContext = context.applicationContext
if (notificationManager == null) {
notificationManager = mContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
initNotifyChannel()
}
}
}
}
return sInstance
}
private fun initNotifyChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (mChannelGroupList == null) {
mChannelGroupList = ArrayList()
}
mChannelGroupList!!.add(NotificationChannelGroup(mContext!!.resources.getString(R.string.groupId_001), "系统消息"))
mChannelGroupList!!.add(NotificationChannelGroup(mContext!!.resources.getString(R.string.groupId_002), "IM消息"))
notificationManager!!.createNotificationChannelGroups(mChannelGroupList!!)
val channel1 = NotificationChannel(mContext!!.resources.getString(R.string.channel_001), "系统消息", NotificationManager.IMPORTANCE_HIGH)
val channel2 = NotificationChannel(mContext!!.resources.getString(R.string.channel_002), "IM消息", NotificationManager.IMPORTANCE_HIGH)
channel1.group = mContext!!.resources.getString(R.string.groupId_001)
channel2.group = mContext!!.resources.getString(R.string.groupId_002)
notificationManager!!.createNotificationChannel(channel1)
notificationManager!!.createNotificationChannel(channel2)
}
}
}
}
其它样式builder的处理逻辑,如 BigTextNotifyBuilder:
package com.let.myapplication
import android.app.Notification
import android.content.Context
import androidx.core.app.NotificationCompat
/**
* @author let
*/
class BigTextNotifyBuilder(defaultBuilder: DefaultNotifyBuilder?) : BaseNotifyBuilder(defaultBuilder!!) {
var mBigText: String? = null
var mBigTextStyle: NotificationCompat.BigTextStyle? = null
fun setBigText(bigText: String?): BigTextNotifyBuilder {
mBigText = bigText
mBigTextStyle = NotificationCompat.BigTextStyle()
.bigText(bigText)
return this
}
override fun build(context: Context?): Notification? {
super.build(context)
notifyBuilder!!.setStyle(mBigTextStyle)
return notifyBuilder!!.build()
}
}