Notification支持文字内容显示、震动、三色灯、铃声等多种提示形式,在默认情况下,Notification仅显示消息标题、消息内容、送达时间这3项内容。
1.更新系统通知Notification显示数据
1.1创建通知
/**
* 创建服务通知
*/
private fun createForegroundNotification(): Notification {
val builder: NotificationCompat.Builder = NotificationCompat.Builder(applicationContext, notificationChannelId)
//通知小图标
builder.setSmallIcon(R.mipmap.ic_launcher_round)
//通知标题
builder.setContentTitle("苏宁窖藏")
//通知内容
builder.setContentText("苏宁是国内优秀的跨国企业?$count")
//设置通知显示的时间
builder.setWhen(System.currentTimeMillis())
//设定启动的内容
val activityIntent: Intent = Intent(this, MainActivity::class.java)
activityIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
val pendingIntent: PendingIntent = PendingIntent.getActivity(this,
1,activityIntent, PendingIntent.FLAG_UPDATE_CURRENT)
builder.setContentIntent(pendingIntent)
builder.priority = NotificationCompat.PRIORITY_DEFAULT
//设置为进行中的通知
builder.setOngoing(true)
//创建通知并返回
return builder.build()
}
1.2更新通知显示内容
- 其中notifyId是通知的唯一标识当通知的notify一致时,再发布通知则会覆盖原有的通知内容;这个方法也常用于实时更新通知内容;
- 前台服务发布通知的方法为startForeground(),使用方法和notificationManager.notify()类似,不需要另外再注册Manager;
主线程更新函数
private var count: Int = 0;
private val handler: Handler = Handler(Looper.getMainLooper());
private val mRunnable: Runnable = object : Runnable {
override fun run() {
val notification: Notification = createForegroundNotification()
//发送通知到状态栏
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//通知更新UI
// notificationManager.notify(NOTIFICATION_ID, notification);
//将服务置于启动状态 ,NOTIFICATION_ID指的是创建的通知的ID
startForeground(NOTIFICATION_ID, notification)
count++
handler.postDelayed(this, 1000)
}
}
2.如何删除关闭通知
1)通过NotificationCompat.Builder 设置setAutoCancel(true) ,这样当用户点击通知后,通知自动删除; 2)通过NotificationManager.cancel(id) 方法,删除指定 id 的通知; 3)通过?NotificationManager.cancelAll() 方法,删除该应用的所有通知;
3.通知栏自定义样式
自定义通知栏我们就要使用RemoteViews了,在SDK为16及以上才支持:
private fun getBigContentView(): RemoteViews{
return RemoteViews(this.packageName, R.layout.notify_big_content_view)
}
private fun getContentView(): RemoteViews{
return RemoteViews(this.packageName, R.layout.notify_content_view)
}
自定义通知栏会有大图样式和小图样式即普通样式和扩展样式,高度上边会有要求限制,普通样式高度不能超过64dp,扩展高度不能超过256dp; 今天我们主要讲一下大小图样式显示的适配; 如果我们可爱的产品和设计妹子给到了优美的大图样式,那我们的设置方法如下:
/**
* 创建服务通知
*/
private fun createForegroundNotification(): Notification {
val builder: NotificationCompat.Builder = NotificationCompat.Builder(applicationContext, notificationChannelId)
//通知小图标
builder.setSmallIcon(R.mipmap.ic_launcher_round)
//通知标题
builder.setContentTitle("苏宁窖藏")
//通知内容
builder.setContentText("苏宁是国内优秀的跨国企业?$count")
//设置通知显示的时间
builder.setWhen(System.currentTimeMillis())
//设定启动的内容
val activityIntent: Intent = Intent(this, MainActivity::class.java)
activityIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
val pendingIntent: PendingIntent = PendingIntent.getActivity(this,
1,activityIntent, PendingIntent.FLAG_UPDATE_CURRENT)
builder.setContentIntent(pendingIntent)
//普通样式(小图样式)
builder.setCustomContentView(getContentView())
//扩展样式(大图样式)
builder.setCustomBigContentView(getBigContentView())
builder.priority = NotificationCompat.PRIORITY_DEFAULT
//设置为进行中的通知
builder.setOngoing(true)
//创建通知并返回
return builder.build()
}
//普通样式视图
private fun getContentView(): RemoteViews{
val remoteViews: RemoteViews = RemoteViews(this.packageName, R.layout.notify_content_view)
return remoteViews
}
//大图样式视图
private fun getBigContentView(): RemoteViews{
return RemoteViews(this.packageName, R.layout.notify_big_content_view)
}
普通样式
builder.setCustomContentView(getContentView())
扩展样式 builder.setCustomBigContentView(getBigContentView())
显示效果如下:
?长按通知显示扩展通知
?4.基于RemoteViews实现音乐播放
4.1创建通知的时候为播放上一集按钮添加监听事件
private fun getBigContentView(): RemoteViews{
bigNormalView = RemoteViews(this.packageName, R.layout.notify_big_content_view)
val intent: Intent = Intent(PLAY_MUSIC)
intent.component = ComponentName("com.yifan.service", "com.yifan.service.PlayBroadcastReceiver")
val pendPreviousButtonIntent = PendingIntent.getBroadcast(this, count++, intent, PendingIntent.FLAG_UPDATE_CURRENT)
//设置播放上一集按钮点击监听
bigNormalView.setOnClickPendingIntent(R.id.play_last, pendPreviousButtonIntent);
//设置播放相关按钮等相关监听操作...
return bigNormalView
}
4.2通过BroadcastReceiver接受点击通知事件
class PlayBroadcastReceiver : BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
if(intent?.action == ForegroundService.Companion.PLAY_MUSIC){
Toast.makeText(context, "播放上一首音乐", Toast.LENGTH_SHORT).show()
//更新UI按钮显示
Single.exe()
}
}
}
使用广播注意事项:
val intent: Intent = Intent(PLAY_MUSIC) ? ? ? ? intent.component = ComponentName("com.yifan.service", "com.yifan.service.PlayBroadcastReceiver") ? ? ? ? val pendPreviousButtonIntent = PendingIntent.getBroadcast(this, count++, intent, PendingIntent.FLAG_UPDATE_CURRENT)
红色代码第1行,指的是要发送一条广播,并且指定了广播的名称,这个跟我们之前注册的广播名称一一对应。
红色代码第2行,在Android 7.0及以下版本不是必须的,但是Android 8.0或者更高版本,发送广播的条件更加严苛,必须添加这一行内容。创建的ComponentName实例化对象有两个参数,第1个参数是指接收广播类的包名,第2个参数是指接收广播类的完整类名。
红色代码第3行,指的是发送广播。
4.3更新通知UI
override fun callback() {
//更新UI显示
bigNormalView.setTextViewText(R.id.play_last, "PlayLast")
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//通知通知UI更新了,更新显示
notificationManager.notify(NOTIFICATION_ID, notification)
}
4.4完整的前台通知服务代码
/**
* 前台服务通知
*/
class ForegroundService : Service(), UpdateUICallback{
companion object{
private const val TAG = "ForegroundService"
//当前服务是否在运行
var serviceIsLive: Boolean = false
//通知ID
private const val NOTIFICATION_ID = 1111
//唯一的通知通道的ID,8.0及以上使用
private const val notificationChannelId = "notification_channel_id_01"
//广播监听器Action
const val PLAY_MUSIC = "com.yifan.service.PLAY_MUSIC"
}
override fun onCreate() {
super.onCreate()
Log.d(TAG,"OnCreate")
//标记服务启动
serviceIsLive = true
//开启前台服务通知
startForegroundWithNotification()
//监听UI更新回调
UpdateSingleInstance.setCallBack(this)
}
override fun onBind(intent: Intent?): IBinder? {
Log.d(TAG,"onBind")
return null
}
override fun onUnbind(intent: Intent?): Boolean {
Log.d(TAG,"onUnbind")
return super.onUnbind(intent)
}
override fun onRebind(intent: Intent?) {
super.onRebind(intent)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG,"onStartCommand")
//数据获取
val data: String? = intent?.getStringExtra("Foreground") ?: ""
Toast.makeText(this, data, Toast.LENGTH_SHORT).show()
return super.onStartCommand(intent, flags, startId)
}
/**
* 开启前景服务并发送通知
*/
private fun startForegroundWithNotification(){
//8.0及以上注册通知渠道
createNotificationChannel()
notification = createForegroundNotification()
// notification.contentView
//将服务置于启动状态 ,NOTIFICATION_ID指的是创建的通知的ID
startForeground(NOTIFICATION_ID, notification)
// handler.postDelayed(mRunnable, 1000)
}
private var count: Int = 0;
private val handler: Handler = Handler(Looper.getMainLooper());
private val mRunnable: Runnable = object : Runnable {
override fun run() {
notification = createForegroundNotification()
// notification.defaults
//发送通知到状态栏
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//通知更新UI
// notificationManager.notify(NOTIFICATION_ID, notification);
//将服务置于启动状态 ,NOTIFICATION_ID指的是创建的通知的ID
startForeground(NOTIFICATION_ID, notification)
count++
handler.postDelayed(this, 1000)
}
}
/**
* 创建通知渠道
*/
private fun createNotificationChannel(){
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//Android8.0以上的系统,新建消息通道
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
//用户可见的通道名称
val channelName: String = "Foreground Service Notification"
//通道的重要程度
val importance: Int = NotificationManager.IMPORTANCE_HIGH
//构建通知渠道
val notificationChannel: NotificationChannel = NotificationChannel(notificationChannelId,
channelName, importance)
notificationChannel.description = "Channel description"
//LED灯
notificationChannel.enableLights(true)
notificationChannel.lightColor = Color.RED
//震动
notificationChannel.vibrationPattern = longArrayOf(0,1000,500,1000)
notificationChannel.enableVibration(true)
//向系统注册通知渠道,注册后不能改变重要性以及其他通知行为
notificationManager.createNotificationChannel(notificationChannel)
}
}
/**
* 创建服务通知
*/
private fun createForegroundNotification(): Notification {
val notificationBuidler = NotificationCompat.Builder(applicationContext, notificationChannelId)
//通知小图标
notificationBuidler.setSmallIcon(R.mipmap.ic_launcher_round)
//通知标题
notificationBuidler.setContentTitle("苏宁窖藏")
//通知内容
notificationBuidler.setContentText("苏宁是国内优秀的跨国企业?$count")
//设置通知显示的时间
notificationBuidler.setWhen(System.currentTimeMillis())
//设定启动的内容
val activityIntent: Intent = Intent(this, MainActivity::class.java)
activityIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
val pendingIntent: PendingIntent = PendingIntent.getActivity(this,
1,activityIntent, PendingIntent.FLAG_UPDATE_CURRENT)
notificationBuidler.setContentIntent(pendingIntent)
notificationBuidler.setCustomContentView(getContentView())
notificationBuidler.setCustomBigContentView(getBigContentView())
notificationBuidler.priority = NotificationCompat.PRIORITY_DEFAULT
//设置为进行中的通知
notificationBuidler.setOngoing(true)
// notificationManager.notify()
//创建通知并返回
return notificationBuidler.build()
}
private lateinit var normalView: RemoteViews
private lateinit var bigNormalView: RemoteViews
private lateinit var notification: Notification
private fun getContentView(): RemoteViews{
normalView = RemoteViews(this.packageName, R.layout.notify_content_view)
// remoteViews.set
// remoteViews.setOnClickFillInIntent()
// remoteViews.setImageViewResource()
//上一首图标添加点击监听
val intent: Intent = Intent(PLAY_MUSIC)
intent.component = ComponentName("com.yifan.service", "com.yifan.service.PlayBroadcastReceiver")
val pendPreviousButtonIntent = PendingIntent.getBroadcast(this, count++, intent, PendingIntent.FLAG_UPDATE_CURRENT)
normalView.setOnClickPendingIntent(R.id.play_last, pendPreviousButtonIntent);
// PendingIntent.get
return normalView
}
private fun getBigContentView(): RemoteViews{
bigNormalView = RemoteViews(this.packageName, R.layout.notify_big_content_view)
val intent: Intent = Intent(PLAY_MUSIC)
intent.component = ComponentName("com.yifan.service", "com.yifan.service.PlayBroadcastReceiver")
val pendPreviousButtonIntent = PendingIntent.getBroadcast(this, count++, intent, PendingIntent.FLAG_UPDATE_CURRENT)
bigNormalView.setOnClickPendingIntent(R.id.play_last, pendPreviousButtonIntent);
return bigNormalView
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy")
stopForeground(true)
ForegroundService.serviceIsLive = false;
handler.removeCallbacks(mRunnable)
}
override fun updateUI() {
// Toast.makeText(this, "播放上一首音乐11111", Toast.LENGTH_SHORT).show()
bigNormalView.setTextViewText(R.id.play_last, "PlayLast")
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(NOTIFICATION_ID, notification)
}
}
/**
* 更新UI回调
*/
interface UpdateUICallback{
fun updateUI()
}
/**
* 更新通信工具类,ForegroundService实现UpdateUICallback接口,
* 广播接收者调用UpdateSingleInstance.updateUI()通知ForegroundService更新UI
*/
object UpdateSingleInstance{
private var updateUICallback: UpdateUICallback? = null
/**
* 注册监听
*/
fun setCallBack(updateUICallback: UpdateUICallback){
this.updateUICallback = updateUICallback
}
fun cancelCallBack(){
this.updateUICallback = null
}
/**
* 通知UpdateSingleInstance更新UI
*/
fun updateUI(){
updateUICallback?.updateUI()
}
}
/**
* 广播接收者接受通知播放点击操作
*/
class PlayBroadcastReceiver : BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
if(intent?.action == ForegroundService.Companion.PLAY_MUSIC){
Toast.makeText(context, "播放上一首音乐", Toast.LENGTH_SHORT).show()
UpdateSingleInstance.updateUI()
}
}
}
Notification通知布局
<?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="horizontal">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@mipmap/ic_launcher"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="流浪的人在外想念你"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/play_last"
android:text="上一首"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暂停"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下一首"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="收藏"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
源码参考:
?服务实例使用
参考:
基于android的网络音乐播放器-通知栏控制(RemoteViews)(十)_xgq330409675的博客-CSDN博客
基于android的网络音乐播放器-通知栏控制(RemoteViews)(十)_xgq330409675的博客-CSDN博客
Android 通知栏自定义样式_stil_king的博客-CSDN博客_android 通知栏自定义android Foreground Service 前台服务/notification全局通知_ex_xyz的博客-CSDN博客_android 前台服务通知
|