Explicação do serviço em primeiro plano do Android, duas visualizações de notificação personalizadas (RemoteViews) e atualização da interface do usuário de dados

A Notificação suporta exibição de conteúdo de texto, vibração, luzes de três cores, toques e outras formas de avisos. Por padrão, a Notificação exibe apenas o título da mensagem, o conteúdo da mensagem e o tempo de entrega .

1. Atualizar os dados de exibição de notificação de notificação do sistema

1.1 Criando notificações

 /**
     * 创建服务通知
     */
    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 Atualizar conteúdo de exibição de notificação

  • O notifyId é o identificador exclusivo da notificação. Quando a notificação da notificação é consistente, o conteúdo da notificação original será substituído se a notificação for emitida novamente. Esse método também é usado frequentemente para atualizar o conteúdo da notificação em tempo real;
  • O método para o serviço de primeiro plano publicar a notificação é startForeground() , o método de uso é semelhante ao notificationManager.notify() , e não há necessidade de registrar o Manager ;

Função de atualização de thread principal

    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. Como remover a notificação de fechamento

1) NotificationCompat.BuilderConfigurando setAutoCancel(true), para que quando o usuário clicar na notificação, a notificação seja automaticamente deletada;
2) Pelo NotificationManager.cancel(id)método, exclua a notificação com o id especificado;
3) Pelo  NotificationManager.cancelAll()método, exclua todas as notificações do aplicativo;

3. Estilo personalizado da barra de notificação

Para personalizar a barra de notificação, usaremos RemoteViews, que é suportado apenas quando o SDK é 16 ou superior :

    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)
    }

A barra de notificação personalizada terá um estilo de imagem grande e um estilo de imagem pequeno, ou seja, o estilo normal e o estilo estendido . Haverá restrições na altura. A altura do estilo normal não pode exceder 64 dp e a altura estendida não pode exceder 256 dp ;
hoje falamos principalmente sobre a exibição dos estilos de imagem grande e pequena. Adaptação;
se nossa adorável garota de produto e design deu um belo estilo de imagem grande, então nosso método de configuração é o seguinte:

/**
     * 创建服务通知
     */
    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)
    }

estilo normal

builder.setCustomContentView(getContentView())

Construtor de estilo estendido.setCustomBigContentView
(getBigContentView())

O efeito de exibição é o seguinte:

 Pressione e segure a notificação para mostrar a notificação estendida

 4. Realize a reprodução de música com base em RemoteViews

4.1 Adicionar um evento de ouvinte para o botão reproduzir o episódio anterior ao criar uma notificação

    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 Aceitar eventos de notificação de clique por meio do 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()
        }
    }
}

Notas sobre o uso de transmissão:

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)

A linha 1 do código vermelho significa que uma transmissão deve ser enviada e o nome da transmissão é especificado, o que corresponde ao nome da transmissão que registramos anteriormente.

A linha 2 do código vermelho não é necessária para o Android 7.0 e inferior, mas para o Android 8.0 ou posterior, as condições de envio de transmissões são mais rigorosas e esta linha deve ser adicionada. O objeto de instanciação ComponentName criado tem dois parâmetros, o primeiro parâmetro refere-se ao nome do pacote da classe de broadcast receptora e o segundo parâmetro refere-se ao nome completo da classe broadcast receptora.

A linha 3 do código vermelho refere-se ao envio de uma transmissão.

4.3 Atualizar IU de notificação

    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 Código completo do serviço de notificação em primeiro plano

/**
 * 前台服务通知
 */
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()
        }
    }
}

Layout de notificação de notificação

<?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>

Referência do código-fonte:

 uso de instância de serviço

referir-se:

Leitor de música em rede baseado em Android - controle da barra de notificação (RemoteViews) (dez) - Programador procurado

Leitor de música em rede baseado em Android - controle da barra de notificação (RemoteViews) (dez) - Programador procurado

Estilo personalizado da barra de notificação do Android

Acho que você gosta

Origin blog.csdn.net/ahou2468/article/details/122523500
Recomendado
Clasificación