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_TASKval 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指的是创建的通知的IDstartForeground(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_TASKval 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//通知IDprivate const val NOTIFICATION_ID = 1111//唯一的通知通道的ID,8.0及以上使用private const val notificationChannelId = "notification_channel_id_01"//广播监听器Actionconst 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指的是创建的通知的IDstartForeground(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指的是创建的通知的IDstartForeground(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_TASKval 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: RemoteViewsprivate lateinit var bigNormalView: RemoteViewsprivate lateinit var notification: Notificationprivate 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.getreturn 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 NotificationManagernotificationManager.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"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"><ImageViewandroid:layout_width="50dp"android:layout_height="50dp"android:src="@mipmap/ic_launcher"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="20dp"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="流浪的人在外想念你"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/play_last"android:text="上一首"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="暂停"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="下一首"/><Buttonandroid: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 前台服务通知

Android前台服务讲解二之自定义通知视图(RemoteViews)及数据UI更新相关推荐

  1. Android绘图机制(二)——自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解

    Android绘图机制(二)--自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解 我们要想画好一些炫酷的View,首先我们得知道怎么去画一些基础的图案,比如矩形,圆 ...

  2. android 前台服务自定义布局不显示_Android前台服务通知未显示

    我正在尝试启动前台服务.我收到通知,该服务确实启动但通知始终被抑制.我仔细检查了应用是否允许在我的设备上的应用信息中显示通知.这是我的代码: private void showNotification ...

  3. android 前台服务自定义布局不显示_Android自定义LinearLayout布局显示不完整的解决方法...

    发现问题 原需求,在一个伸缩列表中,自定义LinearLayout继承LinearLayout动态添加布局. 然而实现的时候:一共遍历了30条数据,却只显示了一条 断点查看代码:遍历addView() ...

  4. Android Service 服务(二)—— BroadcastReceiver

    一. BroadcastReceiver简介 BroadcastReceiver,用于异步接收广播Intent,广播Intent是通过调用Context.sendBroadcast()发送.Broad ...

  5. android前台服务需要解绑,Android接入

    初始化 配置通道服务 必须在应用启动时(Application的onCreate方法中)初始化通道服务配置,所有进程都需要执行.try { // 参考脚手架demo从配置文件获取 Map ipStra ...

  6. Android自定义控件学习(二)-----自定义attr Style styleable以及其应用

    相信每一位从事Android开发的猿都遇到过需要自己去自定义View的需求,如果想通过xml指定一些我们自己需要的参数,就需要自己声明一个styleable,并在里面自己定义一些attr属性,这个过程 ...

  7. Android 项目必备(二十九)-->App 在线升级与更新

    文章目录 前言 实战 前言 1. 用户使用 App 的时候升级提醒有两种方式获得: 通过应用市场获取: 打开应用之后提醒用户更新升级. 2. 更新操作一般是在用户点击了升级按钮之后开始执行的,这里的升 ...

  8. android自定义listview 显示数组,android中使用arrayadapter类的自定义列表视图

    从https://groups.google.com/forum/?fromgroups#!topic/android-developers/No0LrgJ6q2M绘制 public class Ma ...

  9. Android开发笔记(二十九)使用SharedPreferences存取数据

    SharedPreferences使用场景 共享参数(SharedPreferences)是Android上的一个轻量级存储工具,存储结构是类似map的key-value键值对形式.它主要用于保存ap ...

最新文章

  1. sci-learn fit_transform() 与 transform()
  2. Android应用程序组件Content Provider的共享数据更新通知机制分析(3)
  3. 网络攻防 第三周学习总结
  4. 有道智能学习灯 初体验
  5. python中xml模块_python学习第十五天-2(XML模块)
  6. 库克“一语成谶”:又有 30 万台安卓设备被“感染”了!| 文末福利
  7. 2019年技术盘点微服务篇(一) | 程序员硬核评测
  8. Github排序(转载)
  9. UTF8 与 UTF8 +BOM 区别
  10. Python程序:输出斐波那契数列
  11. wpf和winform的那点区别
  12. oracle 用户解锁和修改用户密码
  13. title属性样式 原生dom_HTML DOM title 属性
  14. AI科学计算领域的再突破,昇思MindSpore做“基石”的决心有多强?
  15. 银行家算法C++代码实现
  16. CSDN各产品线月度NPS分析报告新鲜出炉【2021年7月】
  17. layui icon服务器上显示不出来,关于layui的动态图标不显示的解决方法
  18. 伍斯特理工学院计算机科学硕士,美国伍斯特理工学院数据科学硕士录取
  19. Python全栈笔记(六)
  20. Python下载qq音乐歌曲实例教程

热门文章

  1. 优朋otv显示服务器接口异常,睿因路由器产品常见问题及解答汇总
  2. 五、HTML标签——图文详解
  3. CentOS7.6 万兆网卡性能测试.
  4. 如何安装seed_ubantu20.04
  5. linux 最大文件描述符fd
  6. 时间日期格式化(xxx之前)
  7. 卷积层与BN层的融合方式
  8. 【js实现手写签名板】canvas
  9. P1967 货车运输 题解
  10. 一篇文章理解JS中同步任务和异步任务以及宏任务与微任务的原理和执行机制