Android Notification使用教程详解

目录
  • 前言
  • 正文
  • 一、Android中通知的变化
    • 1. Android 4.1,API 16
    • 2. Android 4.4,API 19 和 20
    • 3. Android 5.0,API 21
    • 4. Android 7.0,API 24
    • 5. Android 8.0,API 26
    • 6. Android 12.0,API 31
  • 二、创建项目
  • 三、显示通知
    • ① 创建通知渠道
    • ② 初始化通知
    • ③ 显示通知
  • 四、通知点击
    • ① 创建目的Activity
    • ② PendingIntent使用
  • 五、折叠通知
    • ① 长文本
    • ② 显示图片
  • 六、回复通知
    • ① 创建广播
    • ② RemoteInput
    • ③ PendingIntent
    • ④ NotificationCompat.Action
    • ⑤ 构建通知
  • 七、横幅通知
    • ① 检查横幅通知是否打开
    • ② 构建横幅通知渠道
    • ③ 构建横幅通知
    • ④ 显示横幅通知
  • 八、常驻通知
  • 九、自定义样式通知
    • ① 自定义通知布局
    • ② 显示自定义通知
    • ③ 自定义通知大小
  • 十、源码

前言

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

正文

通知的使用的内容还是比较多的,此篇文章将会尽可能详细的介绍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的项目,如下图所示:

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

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

四、通知点击

在上面的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),下面我们运行一下。

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

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

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

添加位置如下图所示:

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

五、折叠通知

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

① 长文本

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

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

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

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

一行代码搞定:

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

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

运行一下看看

② 显示图片

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

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() {
        ...
        //构建回复pendingIntent
        val replyIntent = Intent(this, ReplyMessageReceiver::class.java)
        val pendingIntent = PendingIntent.getBroadcast(this, 0, replyIntent, PendingIntent.FLAG_ONE_SHOT)
    }

⑤ 构建通知

下面就是构建通知,在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中调用

然后我们在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设置一下就可以了,下面运行一下,看看效果。

十、源码

如果你觉得代码对你有帮助的话,不妨Fork或者Star一下~
GitHub:NotificationStudy

到此这篇关于Android Notification使用的文章就介绍到这了,更多相关Android Notification使用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android使用Notification在状态栏上显示通知

    在使用手机时,当有未接来电或者是新短消息时,手机会给出相应的提示信息,这些提示信息通常会显示到手机屏幕的状态栏上.Android也提供了用于处理此类信息的类,他们是Notification和NotificationManager.其中,Notification代表的是具有全局效果的通知:而NotificationManager则是用于发送Notification通知的系统服务. 使用Notification和NotificationManager类发送和显示通知也比较简单,大致可分为以下4个步骤

  • android使用NotificationListenerService监听通知栏消息

    NotificationListenerService是通过系统调起的服务,在应用发起通知时,系统会将通知的应用,动作和信息回调给NotificationListenerService.但使用之前需要引导用户进行授权.使用NotificationListenerService一般需要下面三个步骤. 注册服务 首先需要在AndroidManifest.xml对service进行注册. <service android:name=".NotificationCollectorService&q

  • Android编程使用Service实现Notification定时发送功能示例

    本文实例讲述了Android编程使用Service实现Notification定时发送功能.分享给大家供大家参考,具体如下: /** * 通过启动或停止服务来管理通知功能 * * @description: * @author ldm * @date 2016-4-29 上午9:15:15 */ public class NotifyControlActivity extends Activity { private Button notifyStart;// 启动通知服务 private Bu

  • Android种使用Notification实现通知管理以及自定义通知栏实例(示例四)

    示例一:实现通知栏管理 当针对相同类型的事件多次发出通知,作为开发者,应该避免使用全新的通知,这时就应该考虑更新之前通知栏的一些值来达到提醒用户的目的.例如我们手机的短信系统,当不断有新消息传来时,我们的通知栏仅仅是更改传来短信的数目,而不是对每条短信单独做一个通知栏用于提示. 修改通知 可以设置一条通知,当然可以更新一条通知,我们通过在调用NotificationManager.notify(ID, notification)时所使用的ID来更新它.为了更新你之前发布的通知,你需要更新或者创建

  • Android使用Notification实现普通通知栏(一)

    Notification是在你的应用常规界面之外展示的消息.当app让系统发送一个消息的时候,消息首先以图表的形式显示在通知栏.要查看消息的详情需要进入通知抽屉(notificationdrawer)中查看.(notificationdrawer)都是系统层面控制的,你可以随时查看,不限制于app. Notification的设计: 作为android UI中很重要的组成部分,notification拥有专属于自己的设计准则. Notification的界面元素在通知抽屉中的notificati

  • Android中通知Notification使用实例(振动、灯光、声音)

    本文实例讲解了通知Notification使用方法,此知识点就是用作通知的显示,包括振动.灯光.声音等效果,分享给大家供大家参考,具体内容如下 效果图: MainActivity: import java.io.File; import android.app.Activity; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; im

  • Android 使用AlarmManager和NotificationManager来实现闹钟和通知栏

    实现闹钟运行的效果如下: 通知栏的运行后效果图如下: 布局文件(activity_main.xml) <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools&qu

  • Android Notification使用教程详解

    目录 前言 正文 一.Android中通知的变化 1. Android 4.1,API 16 2. Android 4.4,API 19 和 20 3. Android 5.0,API 21 4. Android 7.0,API 24 5. Android 8.0,API 26 6. Android 12.0,API 31 二.创建项目 三.显示通知 ① 创建通知渠道 ② 初始化通知 ③ 显示通知 四.通知点击 ① 创建目的Activity ② PendingIntent使用 五.折叠通知 ①

  • Android Notification 使用方法详解

    Android Notification 使用方法详解 用TaskStackBuilder来获取PendingIntent处理点击跳转到别的Activity,首先是用一般的PendingIntent来进行跳转. mBuilder = new NotificationCompat.Builder(this).setContent(view) .setSmallIcon(R.drawable.icon).setTicker("新资讯") .setWhen(System.currentTim

  • Android Notification使用方法详解

    Android  Notification使用详解 Notification 核心代码(链式调用):适用于Android 4.0以上(不兼容低版本) Notification noti = new Notification.Builder(this) .setContentTitle("标题名称") .setContentText("标题里的内容") .setSmallIcon(R.drawable.new_mail) .setLargeIcon(BitmapFac

  • Android  Notification使用方法详解

    Android  Notification使用详解 Notification 核心代码(链式调用):适用于Android 4.0以上(不兼容低版本) Notification noti = new Notification.Builder(this) .setContentTitle("标题名称") .setContentText("标题里的内容") .setSmallIcon(R.drawable.new_mail) .setLargeIcon(BitmapFac

  • Android开发实现带有反弹效果仿IOS反弹scrollview教程详解

    首先给大家看一下我们今天这个最终实现的效果图: 这个是ios中的反弹效果.当然我们安卓中如果想要实现这种效果,感觉不会那么生硬,滚动到底部或者顶部的时候.当然 使用scrollview是无法实现的.所以我们需要新建一个view继承ScrollView package davidbouncescrollview.qq986945193.com.davidbouncescrollview; import android.annotation.SuppressLint; import android.

  • Android Studio开发环境搭建教程详解

    对于移动端这块,笔者之前一直都是进行iOS开发的,也从来没用过Java.但是因为进入了Google Android全国大学生移动互联网创新挑战赛(进入官网)的总决赛(笔者"西部计算机教育提升计划"的项目被直接推荐进入决赛),这个比赛要求一定要提交apk程序,所以我不得不赶紧学习一下Android开发了. 下面就对自己学习的过程做一个记录. 一.安装Android Studio 笔者用的计算机配置如下: Mac下安装Android Studio应该更简单一些,只需要下载一个Android

  • Android Studio 新建项目通过git上传到码云图文教程详解

    作为一个合格的开发人员,对项目进行管理自然必不可少.今天就给各位看客介绍一下如何用git将自己的AS项目上传到码云.    一  创建远程码云代码仓库 首先我们打开码云,注册一个账号,接着在左上角处点击加号新建一个远程的项目仓库用于待会AS项目的上传,具体如下: 按照上图所示,点击创建即生成远程代码仓库.     二 开始进行AS代码的上传 首先我们打开新建好的AS项目,点击AS顶部的如下: 接着点击项目名称如下将项目加入到本地的git仓库中 之后红色的字体会变成绿色. 接着点击顶部vcs上传代

  • android studio 3.4配置Android -jni 开发基础的教程详解

    首先下载配置android studio ndk 1.打开sdkManager下载CMake和LLDB 2.配置ndk 项目新建 项目建立完毕后,工程目录如下,cpp文件夹是系统自动生成的 3.自定义 navite方法 接下来开始写自定义的一个native方法,新建一个Hello.java文件,里面写一个add求和的native方法,如下 生成c++头文件 然后在windows控制台Terminal进入hello.java所在的目录执行javac hello.java,如下 执行完毕后hello

  • Android studio 3.5.2安装图文教程详解

    Android Studio软件下载地址如下: 下载: http://www.android-studio.org/index.php/download Android 工具: https://www.androiddevtools.cn/ 1.下载界面 2.安装 每一步按照我选择的框安装就okay了!!!!! 3.安装完成 4.配置 5.选择界面样式 6.分配空间大小 当然你电脑内存大的话,分配大一点的空间内存 7.配置完成 我这有个小问题,不过没事,你可能不会出现这种问题,如果出现也没事,继

  • android studio编译jar包或者aar包的方法教程详解

    1. 在原有工程目录右键-> new ->Module->: 2. 选择library: 3. 一路next,最后finish: 4. 在新生成的lib module下的build.gradle中添加如下代码: task makeJar(type: Copy) { //删除存在的 delete 'build/outputs/aar/plugin-release.aar' delete 'libs/' //设置拷贝的文件来源 from('build/outputs/aar/') ////新

随机推荐