Android Notification使用

这篇具有很好参考价值的文章主要介绍了Android Notification使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

  在应用的开发中,我们必然会接触到应用通知这个知识,而在通知是随着Android版本进行不断变化,为了能在高版本和低版本中使用,就需要开发者去做适配,也属于查漏补缺。了解之前,先看一个效果图吧。
Android Notification使用

正文

  通知的使用的内容还是比较多的,此篇文章将会尽可能详细的介绍Notification的内容。

一、Android中通知的变化

1. Android 4.1,API 16

  • 推出了展开式通知模板(称为通知样式),可以提供较大的通知内容区域来显示信息。
  • 用户可以通过单指向上/向下滑动的手势来展开通知。还支持以按钮的形式向通知添加其他操作。
  • 允许用户在设置中按应用关闭通知。

2. Android 4.4,API 19 和 20

  • 向 API 中添加了通知监听器服务。
  • API 级别 20 中新增了 Android Wear(现已更名为 Wear OS)支持。

3. Android 5.0,API 21

  • 推出了锁定屏幕和提醒式通知。
  • 用户现在可以将手机设为勿扰模式,并配置允许哪些通知在设备处于“仅限优先事项”模式时打扰他们。
  • 向 API 集添加了通知是否在锁定屏幕上显示的方法 (setVisibility()),以及指定通知文本的“公开”版本的方法。
  • 添加了 setPriority() 方法,告知系统通知的“干扰性”(例如,将其设为“高”可使通知以提醒式通知的形式显示)。
  • 向 Android Wear(现已更名为 Wear OS)设备添加了通知堆栈支持。使用 setGroup() 将通知放入堆栈。请注意,平板电脑和手机尚不支持通知堆栈。通知堆栈以后会称为组或 Bundle。

4. Android 7.0,API 24

  • 重新设置了通知模板的样式以强调主打图片和头像。
  • 添加了三个通知模板:一个用于短信应用,另外两个用于借助展开式选项和其他系统装饰来装饰自定义内容视图。
  • 向手持设备(手机和平板电脑)添加了对通知组的支持。使用与 Android 5.0(API 级别 21)中推出的 Android Wear(现已更名为 Wear OS)通知堆栈相同的 API。
  • 用户可以使用内嵌回复功能直接在通知内进行回复(他们输入的文本将转发到通知的父应用)。

5. Android 8.0,API 26

  • 必须将各个通知放入特定渠道中。
  • 用户可以按渠道关闭通知,而非关闭来自某个应用的所有通知。
  • 包含有效通知的应用将在主屏幕/启动器屏幕上相应应用图标的上方显示通知“标志”。
  • 用户可以从抽屉式通知栏中暂停某个通知。您可以为通知设置自动超时时间。
  • 您还可以设置通知的背景颜色。
  • 部分与通知行为相关的 API 已从 Notification 移至 NotificationChannel。例如,在搭载 Android 8.0 及更高版本的设备中,使用 NotificationChannel.setImportance(),而非 NotificationCompat.Builder.setPriority()。

6. Android 12.0,API 31

  • 自定义通知,提供通知模板。
  • 更改了完全自定义通知的外观和行为。

下面就开始我们的适配之旅吧。

二、创建项目

新建一个名为NotificationStudy的项目,如下图所示:

Android Notification使用

  点击Finish完成项目创建,然后在app的build.gradle中的android{}闭包中开启viewBinding,代码如下:

	buildFeatures {
        viewBinding true
    }

项目创建好之后,我们首先改动一下activity_main.xml布局。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_show"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="显示通知"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

放一个按钮,然后再修改一下MainActivity中的代码,如下所示:

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        //显示通知
        binding.btnShow.setOnClickListener {
            
        }
    }
    
}

  这里就是绑定ViewBinding,然后设置按钮点击监听,下面我们就要开始做显示通知的操作了。

三、显示通知

  常规的通知由三个内容构成:标题、内容和图标。在8.0中还有一个通知渠道,所以我们需要先创建一个通知渠道。

① 创建通知渠道

  创建通知渠道需要三个参数,渠道ID、渠道名称和渠道重要性。

首先在MainActivity中增加几个变量。

	//渠道Id
    private val channelId = "test"
    //渠道名
    private val channelName = "测试通知"
    //渠道重要级
    private val importance = NotificationManagerCompat.IMPORTANCE_HIGH
    //通知管理者
    private lateinit var notificationManager: NotificationManager
    //通知
    private lateinit var notification: Notification
    //通知Id
    private val notificationId = 1

  发送通知首先要通过通知服务得到通知管理者,在onCreate方法中增加如下代码:

	override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        //获取系统通知服务
        notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        
        ...
        }
    }

  然后是创建通知渠道,在MainActivity中新增如下函数。

	/**
     * 创建通知渠道
     */
    @RequiresApi(Build.VERSION_CODES.O)
    private fun createNotificationChannel(channelId: String, channelName: String, importance: Int) =
        notificationManager.createNotificationChannel(NotificationChannel(channelId, channelName, importance))

  因为通知渠道是Android8.0才有的,因此我们添加一个注解,然后将数据构建通知渠道的参数传入进来,注意我们通过notificationManager的createNotificationChannel()函数去创建渠道的,如果notificationManager没有初始化的话,毫无疑问你的这一行代码会报错。

② 初始化通知

  通知渠道创建好了,下面我们去初始化通知,同样在MainActivity中新增一个initNotification()函数,代码如下:

	/**
     * 初始化通知
     */
    private fun initNotification() {
        notification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //创建通知渠道
            createNotificationChannel(channelId,channelName,importance)
            NotificationCompat.Builder(this, channelId)
        } else {
            NotificationCompat.Builder(this)
        }.apply {
            setSmallIcon(R.mipmap.ic_launcher)//小图标(显示在状态栏)
            setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))//大图标(显示在通知上)
            setContentTitle("打工人")//标题
            setContentText("我要搞钱!!!")//内容
        }.build()
    }

  这里首先通过版本判断检查是否需要创建通知渠道,然后会得到一个通知的Builder,通过Builder去配置通知所需要的基本参数,这里我设置了图标,标题,内容,配置完之后调用build(),完成通知的构建,最后返回一个notification,现在我们的通知就构建好了。

③ 显示通知

然后我们再修改一下onCreate中的代码,如下所示

	override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        //获取系统通知服务
        notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        //初始化通知
        initNotification()
        //显示通知
        binding.btnShow.setOnClickListener {
            notificationManager.notify(notificationId, notification)
        }
    }

这里我们调用了initNotification()函数,然后在点击按钮时发送通知。

	binding.btnShow.setOnClickListener {
		notificationManager.notify(notificationId, notification)
	}

运行一下,效果如下图所示:

Android Notification使用

四、通知点击

  在上面的gif中,我们成功显示了通知,其中我们尝试去做了点击通知的动作,但是没有什么反应,因为这方面的功能还没有写,下面我们就来写。

  首先要想一下点击之后要干嘛?通常来说都是跳转到指定的Activity,我们当前只有一个MainActivity,因此我们需要创建一个。

① 创建目的Activity

  我们在com.llw.notification下创建DetailsActivity,对应activity_details.xml布局文件,修改一下布局文件,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".DetailsActivity">

    <TextView
        android:id="@+id/tv_notification_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

这里增加一个TextView,然后回到DetailsActivity中,修改代码如下:

class DetailsActivity : AppCompatActivity() {

    private lateinit var binding: ActivityDetailsBinding

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityDetailsBinding.inflate(layoutInflater)
        setContentView(binding.root)

        intent?.let {
            binding.tvNotificationContent.text =
                "${it.getStringExtra("title")}\n" + "${it.getStringExtra("content")}"
        }
    }
}

  这里的代码也很简单,就是获取传递过来的intent中携带的参数显示在TextView上,假设我们在MainActivity中点击时传递title和content。

② PendingIntent使用

  我们经常使用Intent,但是接触PendingIntent是比较少的,PendingIntent可以看作是对Intent的一个封装,但它不是立刻执行某个行为,而是满足某些条件或触发某些事件后才执行指定的行为。

  PendingIntent获取有三种方式:Activity、Service和BroadcastReceiver获取。PendingIntent有一个比较简单的使用方式,例如我们现在要在Activity中使用,修改initNotification()函数中的代码:

	private fun initNotification() {
        val title = "打工人"
        val content = "我要搞钱!!!"
        // 为DetailsActivity 创建显式 Intent
        val intent = Intent(this, DetailsActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
            putExtra("title", title).putExtra("content", content)
        }
        val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0)

        notification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //创建通知渠道
            createNotificationChannel(channelId, channelName, importance)
            NotificationCompat.Builder(this, channelId)
        } else {
            NotificationCompat.Builder(this)
        }.apply {
            setSmallIcon(R.mipmap.ic_launcher)//小图标(显示在状态栏)
            setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))//大图标(显示在通知上)
            setContentTitle(title)//标题
            setContentText(content)//内容
            setContentIntent(pendingIntent)//设置内容意图
        }.build()
    }

  这里的代码解释一下,首先将title、content抽离出来,然后创建intent,再创建pendingIntent 。最后在配置build中设置setContentIntent(pendingIntent),下面我们运行一下。

Android Notification使用
  这里已经完成了点击通知并传递的操作,这里还有一个细节就是常规来说我们点击了这个通知表示我们已经看到了,或者已经知晓了内容,因此通知就会消失,而这里通知并没有消息。

只需要一个配置就可以做到。

setAutoCancel(true)//设置自动取消

添加位置如下图所示:

Android Notification使用
运行测试一下就行,我就不用gif说明了。

五、折叠通知

  有时候我们设置通知的内容可能一行放不下,这个时候就需要收缩和展开通知,让用户看到完整的信息。

① 长文本

现在我将content的内容修改一下:

val content = "我要搞钱!!!富强、明主、文明、和谐、自由、平等、公正、法治、爱国、敬业、诚信、友善"

然后我们什么都不做去运行看看。

Android Notification使用
  这里并没有显示多行,同时也没有那个向下展开的按钮,内容文字做了省略,因此这说明那个展开需要我们去设置。

一行代码搞定:

setStyle(NotificationCompat.BigTextStyle().bigText(content))

  通过设置通知的风格样式,这里使用的是长文本信息样式,将content传递进去。添加位置如下图所示:

Android Notification使用

运行一下看看

Android Notification使用

② 显示图片

  有时候我们会在通知中展开时看到图片,实际上就是使用了另一个样式,也是一行代码解决。

setStyle(NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(resources,R.drawable.logo)))//设置样式

  这行代码的位置和替换掉刚才哪一行,通知只能设置一个样式,后面设置的样式会覆盖掉前面的样式,这里我们使用大图片样式,传进入一个logo.jpg图片,你在写的时候随便用什么都行,然后我们再运行一下。

在这里插入图片描述

六、回复通知

  有时候我们的手机收到短信消息,是可以直接回复的。当然了这个功能是需要手动去写的。流程就是点击按钮出现一个通知,通知中回复消息,广播或服务收到消息后更新通知,然后关闭通知。

① 创建广播

  这里我们先来写这个接收回复消息的处理,这里用广播来处理,首先我们需要创建一个广播,在com.llw.notification下新建一个ReplyMessageReceiver类,里面的代码如下:

class ReplyMessageReceiver : BroadcastReceiver() {

    private val TAG = ReplyMessageReceiver::class.java.simpleName

    override fun onReceive(context: Context, intent: Intent) {
        //获取回复消息的内容
        val inputContent =
            RemoteInput.getResultsFromIntent(intent)?.getCharSequence("key_text_reply")?.toString()
        Log.d(TAG, "onReceive: $inputContent")
  
        if (inputContent == null) {
            Log.e(TAG, "onReceive: 没有回复消息!")
            return
        }
        //构建回复消息通知
        val repliedNotification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationCompat.Builder(context, "reply")
        } else {
            NotificationCompat.Builder(context)
        }.apply {
            setSmallIcon(R.mipmap.ic_launcher)//小图标(显示在状态栏)
            setContentTitle("1008666")//标题
            setContentText("消息发送成功!")//内容
        }.build()

        val notificationManager =
            context.getSystemService(AppCompatActivity.NOTIFICATION_SERVICE) as NotificationManager
        //发送通知
        notificationManager.notify(2, repliedNotification)
        //1秒后取消通知
        Timer().schedule(1000){
            notificationManager.cancel(2)
        }
    }
}

  这里说明一下:首先是RemoteInput表示远程输入,也就是通知栏上输入框,这里就是获取输入框的内容,注意"key_text_reply"这个值,我们在构建RemoteInput时使用的值要与这个一致,不一致你在广播中就拿不到输入的值。

  然后是构建通知了,这里的设置都是常规操作,渠道id我是写死的,因此在Activity中创建通知时渠道Id也要一致。最后就是在发送通知之后加了一个1秒的延时去取消通知,表示收到回复的处理。

广播是需要在AndroidManifest.xml注册的,代码如下:

<receiver android:name=".ReplyMessageReceiver"/>

位置如下:
在这里插入图片描述

  下面就是要构建回复通知了。因为要区别于之前的普通通知,所以这里我需要更改一下activity_main.xml中的布局代码

	<Button
        android:id="@+id/btn_show_reply"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="显示回复通知"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_show" />

增加一个按钮,点击事件后面再写。

② RemoteInput

为了区分普通通知和回复通知,在MainActivity中定义一下。

	//回复通知Id
    private val replyNotificationId = 2
    //回复通知
    private lateinit var replyNotification: Notification

下面我们新建一个initReplyNotification()函数,在里面对RemoteInput进行构建。

	private fun initReplyNotification() {
        //远程输入
        val remoteInput = RemoteInput.Builder("key_text_reply").setLabel("快速回复").build()
    }

  这里RemoteInput的构建也很简单,最关键的就是"key_text_reply",刚才在适配器中已经说了,而Label就是一个输入框的提示文本。

③ PendingIntent

  现在我们要通过BroadcastReceiver获取PendingIntent,在initReplyNotification()函数中新增代码:

	private fun initReplyNotification() {
        ...
        //构建回复pendingIntent
        val replyIntent = Intent(this, ReplyMessageReceiver::class.java)
        val pendingIntent = PendingIntent.getBroadcast(this, 0, replyIntent, PendingIntent.FLAG_ONE_SHOT)
    }

④ NotificationCompat.Action

  通知动作,我们在输入框写入信息,需要一个按钮发送这个按钮,这个Action就是用来做这个事情的,在initReplyNotification()函数中新增代码:

	private fun initReplyNotification() {
        ...
        //点击通知的发送按钮
        val action = NotificationCompat.Action.Builder(0, "回复", pendingIntent).addRemoteInput(remoteInput).build()
    }

⑤ 构建通知

下面就是构建通知,在initReplyNotification()函数中新增代码:

	private fun initReplyNotification() {
        ...
        //构建通知
        replyNotification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createNotificationChannel("reply", "回复消息", importance)
            NotificationCompat.Builder(this, "reply")
        } else {
            NotificationCompat.Builder(this)
        }.apply {
            setSmallIcon(R.mipmap.ic_launcher)//小图标(显示在状态栏)
            setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))//大图标(显示在通知上)
            setContentTitle("1008666")//标题
            setContentText("你的账号已欠费2000元!")//内容
            addAction(action)
        }.build()
    }

这里的关键就在于这个addAction(action),下面我们运行一下:

在这里插入图片描述
然后我们看看日志:

在这里插入图片描述

七、横幅通知

  横幅通知我相信你一定见过,例如收到短信、QQ、微信、钉钉的消息,都会有出现在屏幕顶部,主要是用于提醒用户的。

首先我们修改布局,在activity_main.xml中新增一个按钮,代码如下:

	<Button
        android:id="@+id/btn_show_banner"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="显示横幅通知"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_show_reply" />

① 检查横幅通知是否打开

首先在MainActivity中定义几个变量

	//横幅通知
    private lateinit var bannerNotification: Notification
    //横幅通知Id
    private val bannerNotificationId = 3
    //开启横幅通知返回
    private val bannerLauncher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            if (it.resultCode == RESULT_OK) {
                Log.d("TAG", "返回结果")
            }
        }

然后新增一个openBannerNotification()函数,代码如下:

	private fun openBannerNotification() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val bannerImportance = notificationManager.getNotificationChannel("banner").importance
        if (bannerImportance == NotificationManager.IMPORTANCE_DEFAULT) {
            val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
                .putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
                .putExtra(Settings.EXTRA_CHANNEL_ID, "banner")
            bannerLauncher.launch(intent); false
        } else true
    } else true

这里通过检查通知遇到的重要级判断是否开启横幅通知。

② 构建横幅通知渠道

在MainActivity中新增createBannerNotificationChannel()函数,代码如下:

	@RequiresApi(Build.VERSION_CODES.O)
    private fun createBannerNotificationChannel(channelId: String, channelName: String, importance: Int) =
        notificationManager.createNotificationChannel(
            NotificationChannel(channelId, channelName, importance).apply {
                description = "提醒式通知"//渠道描述
                enableLights(true)//开启闪光灯
                lightColor = Color.BLUE//设置闪光灯颜色
                enableVibration(true)//开启震动
                vibrationPattern = longArrayOf(0, 1000, 500, 1000)//震动模式
                setSound(null, null)//没有提示音
            }
        )

这里的内容相对于之前来说就多一些,有注释也好理解。

③ 构建横幅通知

在MainActivity中新增initBannerNotification()函数,代码如下:

	private fun initBannerNotification() {
        //构建通知
        bannerNotification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createBannerNotificationChannel("banner", "提醒消息", importance)
            NotificationCompat.Builder(this, "banner")
        } else {
            NotificationCompat.Builder(this)
        }.apply {
            setSmallIcon(R.mipmap.ic_launcher)//小图标(显示在状态栏)
            setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))//大图标(显示在通知上)
            setContentTitle("落魄Android在线炒粉")//标题
            setContentText("不要9块9,不要6块9,只要3块9。")//内容
            setWhen(System.currentTimeMillis())//通知显示时间
            setAutoCancel(true)//设置自动取消
        }.build()
    }

这里也就是一些常规的设置。

④ 显示横幅通知

最后我们在onCreate()函数中,新增如下代码:

		//显示横幅通知
        binding.btnShowBanner.setOnClickListener {
            //检查是否授予访问权限
            if (openBannerNotification()) {
                notificationManager.notify(bannerNotificationId, bannerNotification)
            }
        }

下面我们运行一下:

在这里插入图片描述
OK,这样就可以了。

八、常驻通知

  我们知道有一些通知,当程序运行的时候就会出现,例如我们最常见的音乐类App,而且这个通知并不是马上出现的,在此之前还有很多内容要初始化,一切就绪之后出现这个通知,就可以通过通知去控制音乐了。

在这里插入图片描述

  我们并不需要这种复杂的操作,只有有一个通知能在App启动的时候显示出来,并且App进入后台时,通知也还在。

在MainActivity创建变量。

	//常驻通知
    private lateinit var permanentNotification: 
    //常驻通知Id
    private val permanentNotificationId = 4Notification

然后在MainActivity中新增一个showPermanentNotification()函数,代码如下:

	private fun showPermanentNotification() {
        //构建回复pendingIntent
        val permanentIntent = Intent(this, MainActivity::class.java)
        val pendingIntent =
            PendingIntent.getActivity(this, 0, permanentIntent, PendingIntent.FLAG_UPDATE_CURRENT)
        //构建通知
        permanentNotification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createNotificationChannel("permanent", "我一直存在", importance)
            NotificationCompat.Builder(this, "permanent")
        } else {
            NotificationCompat.Builder(this)
        }.apply {
            setSmallIcon(R.mipmap.ic_launcher)//小图标(显示在状态栏)
            setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))//大图标(显示在通知上)
            setContentTitle("你在努力些什么?")//标题
            setContentText("搞钱!搞钱!还是搞钱!")//内容
            setWhen(System.currentTimeMillis())//通知显示时间
            setContentIntent(pendingIntent)
        }.build()
        permanentNotification.flags = Notification.FLAG_ONGOING_EVENT
        notificationManager.notify(permanentNotificationId, permanentNotification)
    }

  这里就很简单了,主要就是去掉通知取消设置,同时设置FLAG_ONGOING_EVENT,另外在点击通知的时候进入主页面。在onCreate()函数中调用。

在这里插入图片描述
运行一下:

在这里插入图片描述
  可以看到这里我用别的通知显示出来之后,清理一下,其他通知就没有了,而常驻通知还在,然后我程序进入后台,点击常驻通知,又会启动到前台。

九、自定义样式通知

  现在我们使用的都是常规的样式通知,实际上我们可以自定义的,就是自定义通知布局,我们先来设计自定义布局的样式,就做一个音乐通知栏吧,首先是三个图标。

① 自定义通知布局

在drawable文件夹下新建ic_previous.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="36dp"
    android:height="36dp"
    android:tint="@color/white"
    android:viewportWidth="24.0"
    android:viewportHeight="24.0">
    <path
        android:fillColor="@android:color/white"
        android:pathData="M7,6c0.55,0 1,0.45 1,1v10c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L6,7c0,-0.55 0.45,-1 1,-1zM10.66,12.82l5.77,4.07c0.66,0.47 1.58,-0.01 1.58,-0.82L18.01,7.93c0,-0.81 -0.91,-1.28 -1.58,-0.82l-5.77,4.07c-0.57,0.4 -0.57,1.24 0,1.64z" />
</vector>

ic_play.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="36dp"
    android:height="36dp"
    android:tint="@color/white"
    android:viewportWidth="24.0"
    android:viewportHeight="24.0">
    <path
        android:fillColor="@android:color/white"
        android:pathData="M8,6.82v10.36c0,0.79 0.87,1.27 1.54,0.84l8.14,-5.18c0.62,-0.39 0.62,-1.29 0,-1.69L9.54,5.98C8.87,5.55 8,6.03 8,6.82z" />
</vector>

ic_next.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="36dp"
    android:height="36dp"
    android:tint="@color/white"
    android:viewportWidth="24.0"
    android:viewportHeight="24.0">
    <path
        android:fillColor="@android:color/white"
        android:pathData="M7.58,16.89l5.77,-4.07c0.56,-0.4 0.56,-1.24 0,-1.63L7.58,7.11C6.91,6.65 6,7.12 6,7.93v8.14c0,0.81 0.91,1.28 1.58,0.82zM16,7v10c0,0.55 0.45,1 1,1s1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1z" />
</vector>

然后在layout下新建一个layout_custom_notification.xml,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/black"
    android:gravity="center_vertical">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_song_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:text="雨下一整晚"
            android:textColor="@color/white"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/tv_singer"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginTop="4dp"
            android:text="周杰伦"
            android:textColor="@color/white"
            android:textSize="12sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center">

        <ImageButton
            android:id="@+id/iv_previous"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@null"
            android:src="@drawable/ic_previous" />

        <ImageButton
            android:id="@+id/iv_play"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginEnd="16dp"
            android:background="@null"
            android:src="@drawable/ic_play" />

        <ImageButton
            android:id="@+id/iv_next"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@null"
            android:src="@drawable/ic_next" />
    </LinearLayout>

    <ImageView
        android:id="@+id/iv_avatar"
        android:layout_width="72dp"
        android:layout_height="72dp"
        android:src="@drawable/jay" />
</LinearLayout>

  这里要注意一点自定义通知的界面布局只支持LinearLayout、RelativeLayout、FrameLayout,目前不支持ConstraintLayout通知布局里有ConstraintLayout的话,弹通知不会显示。

jpg图标用自己的,或者用我源码里面都可以,然后就很简单了,回到MainActivity。

② 显示自定义通知

	//自定义通知
    private lateinit var customNotification: Notification
    //自定义通知Id
    private val customNotificationId = 5

然后创建initCustomNotification()函数,代码如下:

	@SuppressLint("RemoteViewLayout")
    private fun initCustomNotification() {
        //RemoteView
        val remoteViews = RemoteViews(packageName, R.layout.layout_custom_notification)
        customNotification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createNotificationChannel("custom", "自定义通知", importance)
            NotificationCompat.Builder(this, "custom")
        } else {
            NotificationCompat.Builder(this)
        }.apply {
            setSmallIcon(R.mipmap.ic_launcher)//小图标(显示在状态栏)
            setCustomContentView(remoteViews)//设置自定义内容视图
            setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
            setOnlyAlertOnce(true)
            setOngoing(true)
        }.build()
    }

在onCreate中调用

c

然后我们在activity_main.xml中新增一个按钮:

	<Button
        android:id="@+id/btn_show_custom"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="显示自定义通知"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_show_banner" />

最后在MainActivity中的onCreate()函数中新增按钮点击事件,同时点击调用通知显示:

		//显示自定义通知
        binding.btnShowCustom.setOnClickListener {
            notificationManager.notify(customNotificationId, customNotification)
        }

运行一下:
在这里插入图片描述

③ 自定义通知大小

  通知布局视图布局的高度上限为 64 dp,展开后的视图布局的高度上限为 256 dp,刚才我们只设置了小的通知,那么如果要展开一个大一点的通知,最好是能够滑动通知的时候有大小变化。

  其实很简单,首先我们同样要定义一个大一点同通知布局,在layout下新建一个layout_custom_notification_big.xml,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/black"
    android:gravity="center_vertical">

    <TextView
        android:id="@+id/tv_song_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:text="雨下一整晚"
        android:textColor="@color/white"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_singer"
        android:layout_below="@+id/tv_song_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="6dp"
        android:text="周杰伦"
        android:textColor="@color/white"
        android:textSize="16sp" />

    <LinearLayout
        android:layout_marginTop="16dp"
        android:layout_below="@+id/tv_singer"
        android:layout_alignParentStart="true"
        android:layout_toStartOf="@+id/iv_avatar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center">

        <ImageButton
            android:id="@+id/iv_previous"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@null"
            android:src="@drawable/ic_previous" />

        <ImageButton
            android:id="@+id/iv_play"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginEnd="16dp"
            android:background="@null"
            android:src="@drawable/ic_play" />

        <ImageButton
            android:id="@+id/iv_next"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@null"
            android:src="@drawable/ic_next" />
    </LinearLayout>

    <ImageView
        android:layout_alignParentEnd="true"
        android:id="@+id/iv_avatar"
        android:layout_width="144dp"
        android:layout_height="144dp"
        android:src="@drawable/jay" />
</RelativeLayout>

然后我们修改initCustomNotification()函数中的代码:

	@SuppressLint("RemoteViewLayout")
    private fun initCustomNotification() {
        //RemoteView
        val remoteViews = RemoteViews(packageName, R.layout.layout_custom_notification)
        val bigRemoteViews = RemoteViews(packageName, R.layout.layout_custom_notification_big)
        customNotification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createNotificationChannel("custom", "自定义通知", importance)
            NotificationCompat.Builder(this, "custom")
        } else {
            NotificationCompat.Builder(this)
        }.apply {
            setSmallIcon(R.mipmap.ic_launcher)//小图标(显示在状态栏)
            setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
            setCustomContentView(remoteViews)
            setCustomBigContentView(bigRemoteViews)
            setOnlyAlertOnce(true)
            setOngoing(true)
        }.build()
    }

  我们再创建一个RemoteView,然后通过setCustomBigContentView设置一下就可以了,下面运行一下,看看效果。

Android Notification使用

十、源码

如果你觉得代码对你有帮助的话,不妨Fork或者Star一下~
GitHub:NotificationStudy文章来源地址https://www.toymoban.com/news/detail-404242.html

到了这里,关于Android Notification使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 对于Android开发,我们为何要学Jetpack Compose?

    Jetpack Compose 是用于构建原生 Android 界面的新工具包。它可简化并加快 Android 上的界面开发,使用更少的代码、强大的工具和直观的 Kotlin API,快速让应用生动而精彩。Compose 使用全新的组件——可组合项 (Composable) 来布局界面,使用修饰符 (Modifier) 来配置可组合项。 为何Jetp

    2024年02月10日
    浏览(38)
  • 使用 GPT4 和 ChatGPT 开发应用:前言到第三章

    原文:Developing Apps with GPT-4 and ChatGPT 译者:飞龙 协议:CC BY-NC-SA 4.0 在发布仅仅五天后,ChatGPT 就吸引了惊人的一百万用户,这在科技行业及其他领域引起了轰动。作为一个副作用,OpenAI API 用于人工智能文本生成的接口突然曝光,尽管它已经可用了三年。ChatGPT 界面展示了这

    2024年01月20日
    浏览(67)
  • Android 之 Notification (状态栏通知)详解

    本节带来的是Android中用于在状态栏显示通知信息的控件:Notification,相信大部分 学Android都对他都很熟悉,而网上很多关于Notification的使用教程都是基于2.x的,而 现在普遍的Android设备基本都在4.x以上,甚至是5.0以上的都有;他们各自的Notification 都是不一样的!而本节给大家

    2024年02月15日
    浏览(35)
  • Android Studio Notification(状态栏通知) 不显示通知 解决

    引言:在学习的过程中,我发现,无论怎么修改,甚至是直接复制了大佬的代码,我的程序都不能正确的弹出状态栏通知,在经过一晚上的纠缠后,终于找到了原因 通知不显示 可能由多种原因引起: 通知权限:确保你的应用已经获得了正确的通知权限。在Android设备上,用户

    2024年02月16日
    浏览(40)
  • android.app.RemoteServiceException: Bad notification for startForeground

    异常如下: 解决方法是 在 Android 8.0上 创建一个 NotificationChannel,代码如下 2 Android 中的 Service Service 是一种可在后台执行长时间运行操作而不提供界面的应用组件。 服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可通过绑

    2024年02月12日
    浏览(47)
  • Android - app内部通知通知栏通知Notification (Kotlin)

    一、简述 先把通知权限打开 为什么写,因为在学kotlin刚好顺手写一下,整块代码在最后 图示效果:(图片来源于网络) 1、首先需要一个NotificationManager对通知进行管理,可以通过调用Context的 getSystemService()方法获取。getSystemService()方法接收一个字符串参数用于确定 获取系统的

    2024年02月08日
    浏览(36)
  • flutter开发实战-实现推送功能Push Notification

    flutter开发实战-实现推送功能Push Notification 推送服务现在可以说是所有 App 的标配了,最近在Flutter工程项目上实现推送功能。flutter上实现推送功能需要依赖原生的功能,需要插件实现,这里使用的是极光推送的服务。 效果图如下 在使用极光推送功能时,需要使用的是极光提

    2024年02月16日
    浏览(40)
  • Android System Property讲解前言

    我们在开发过程中经常会使用到系统属性,例如获取系统软件版本,获取设备名名称,boardid等;有时也需要内置自己的属性,系统属性简单来说是用来存储系统中某些键值对数据,具有全局性、存取灵活方便的特点。 setprop 可以给属性设置int,bool,string等基本类型 在java代码中

    2024年02月07日
    浏览(35)
  • uniapp 开发App使用微信H5支付解决方案(包含前后端,后端用的thinkphp)

    我们在开发app常常需要接入支付功能,但是有时候出于包体积或审核的因素,并不想接入支付相关的sdk,这个时候,就可以考虑使用 h5支付 完成购买服务,只需要访问后端返回的 h5支付链接 即可,便捷而简单。 话不多说,进入正题! 前往微信商户平台 - 产品中心 - 我的产品

    2024年02月06日
    浏览(39)
  • 十三、使用Github Copilot 来提升我们的开发效率和使用技巧

    这段时间通过使用 github copilot 来辅助开发所总结的一些使用感受,来分享给大家 GitHub Copilot 是由 Github 和 OpenAI 创造的 AI 工具。该工具通过自动代码补全来帮助程序员们编写代码。Visual Studio Code、Neovim 和 JetBrains 的用户已经可以使用这个插件了。 GitHub Copilot 基于 OpenAI Codex

    2024年02月12日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包