IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android前台服务讲解二之自定义通知视图(RemoteViews)及数据UI更新 -> 正文阅读

[移动开发]Android前台服务讲解二之自定义通知视图(RemoteViews)及数据UI更新

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 前台服务通知

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-01-17 11:36:04  更:2022-01-17 11:37:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:34:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码