定时消息提醒的实现
前言
项目开发的待办模块需要实现待办提醒,也就是定时弹出通知消息。一开始的思路是AlarmManager+BoardcastReceiver+Notification,也就是设置闹钟管理定时通知广播来弹出通知框。最后的实现方法是通过定时器+Notification的方式。具体实现如下:
1、创建接口管理通知任务
/**
* 添加一条待办通知
*/
fun insertOrUpdateTodo(todoInfo: TodoInfo)
/**
* 添加待办通知
*/
fun inserts(todoInfo: List<TodoInfo>)
/**
* 删除一条待办通知
*/
fun remove(todoInfoId: Long)
/**
* 删除所有待办通知
*/
fun removeAll()
2、实现接口,将任务加入定时器中
private val todoMap = mutableMapOf<Long, TimerTask>()
override fun insertOrUpdateTodo(todoInfo: TodoInfo) {
SpeedyLog.i(TAG, "insertOrUpdateTodo todoInfo=$todoInfo")
//移除已存在的任务
todoMap.remove(todoInfo.id)?.cancel()
//过滤不是今天的
if (!todoInfo.isToday){
SpeedyLog.i(TAG, "任务不是今天的,不加入定时器")
return
}
//过滤已完成的
if (todoInfo.isOver()){
SpeedyLog.i(TAG, "任务已完成,不加入定时器")
return
}
var delayTime = todoInfo.getTodoDelayTime()
SpeedyLog.i(TAG, "delayTime is $delayTime")
if (delayTime > 0){
mTimer.schedule(SafeTask {
SpeedyLog.i(TAG, "${todoInfo.id}定时器触发,消息弹窗提醒")
//移除保存map
todoMap.remove(todoInfo.id)
//消息弹窗提醒
TodoNotification().showNotify(todoInfo)
}.also {
todoMap[todoInfo.id] = it
}, delayTime)
}else{
SpeedyLog.i(TAG, "delayTime < 0,不加入定时器")
}
}
override fun inserts(todoInfos: List<TodoInfo>) {
todoInfos.forEach{
insertOrUpdateTodo(it)
}
}
override fun remove(todoInfoId: Long) {
SpeedyLog.i(TAG, "移除任务 todoInfoId=$todoInfoId")
todoMap.remove(todoInfoId)?.cancel()
}
override fun removeAll() {
SpeedyLog.i(TAG, "移除所有任务")
todoMap.forEach {
it.value.cancel()
}
todoMap.clear()
}
3、显示到通知栏
fun showNotify(todoInfo: TodoInfo) {
binding = LayoutTodoNotifyItemBinding.inflate(context.layoutInflater())
val notificationLayout =
RemoteViews(context.packageName, R.layout.layout_todo_notify_item)
val notifyAfterI = Intent().setAction(TodoNotifyReceiver.TODO_CHANGE_ACTION)
val alreadyKnowI = Intent().setAction(TodoNotifyReceiver.TODO_ALREADY_KNOW_ACTION)
notifyAfterI.putExtra("todoInfo", todoInfo)
alreadyKnowI.putExtra("todoInfo", todoInfo)
val intent = Intent(context, MarketActivity::class.java)
val pendingIntent =
PendingIntent.getActivity(
context,
todoInfo.id.toInt(),
intent,
PendingIntent.FLAG_CANCEL_CURRENT
)
var notifyAfterPI =
PendingIntent.getBroadcast(
context,
todoInfo.id.toInt(),
notifyAfterI,
PendingIntent.FLAG_CANCEL_CURRENT
)
var alreadyKnowPI =
PendingIntent.getBroadcast(
context,
todoInfo.id.toInt(),
alreadyKnowI,
PendingIntent.FLAG_CANCEL_CURRENT
)
notificationLayout.setOnClickPendingIntent(R.id.notify_after, notifyAfterPI)
notificationLayout.setOnClickPendingIntent(R.id.already_know, alreadyKnowPI)
notificationLayout.setTextViewText(R.id.notify_content, todoInfo.content)
notificationLayout.setTextViewText(
R.id.notify_date,
"${todoInfo.year}-${todoInfo.month}-${todoInfo.day} ${todoInfo.time}"
)
var notifyBuild: NotificationCompat.Builder? = null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
var notificationChannel =
NotificationChannel(
context.packageName,
"todoNotify",
NotificationManager.IMPORTANCE_HIGH
)
notificationChannel.lockscreenVisibility = Notification.VISIBILITY_SECRET
notificationChannel.enableLights(true); //是否在桌面icon右上角展示小红点
notificationChannel.lightColor = Color.RED; //小红点颜色
notificationChannel.setShowBadge(true); //是否在久按桌面图标时显示此渠道的通知
notificationManager.createNotificationChannel(notificationChannel)
notifyBuild = NotificationCompat.Builder(context, todoInfo.id.toString())
notifyBuild.setChannelId(context.packageName);
} else {
notifyBuild = NotificationCompat.Builder(context)
}
notifyBuild.setSmallIcon(R.mipmap.icon_todo_item_normal)
.setStyle(NotificationCompat.DecoratedCustomViewStyle())
.setCustomContentView(notificationLayout)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.build()
notificationManager.notify(todoInfo.id.toInt(), notifyBuild.build())
}
通知的自定义布局中有两个按钮监听,这里是通过动态注册广播来实现的。
4、注册并实现监听
private fun initTodoNotifyEvent() {
TodoNotifyReceiver.registerTodoNotifyReceiver(context, {
//更新待办提醒时间
TodoScheduleUseCase().delayTodoTask5min(it)
TodoNotification().cancelNotifyById(it.id.toInt())
}) {
//已知悉,标记已完成
TodoScheduleUseCase().markTodoTaskDone(it)
TodoNotification().cancelNotifyById(it.id.toInt())
}
}
fun registerTodoNotifyReceiver(
context: Context,
block: (todoInfo: TodoInfo) -> Unit,
block2: (todoInfo: TodoInfo) -> Unit
) {
context.registerReceiver(TodoNotifyReceiver(block, block2), IntentFilter().apply {
addAction(TODO_CHANGE_ACTION)
addAction(TODO_ALREADY_KNOW_ACTION)
})
}
private val TAG = MdmConstant.BaseTAG + TodoNotifyReceiver::class.java.simpleName
var TODO_CHANGE_ACTION = "android.intent.action.ACTION_TODO_CHANGE"
var TODO_ALREADY_KNOW_ACTION = "android.intent.action.ACTION_ALREADY_KNOW"
}
class TodoNotifyReceiver(
private val block: (todoInfo: TodoInfo) -> Unit,
private val block2: (todoInfo: TodoInfo) -> Unit
) : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
intent.let { intent ->
val todoInfo = intent.getSerializableExtra("todoInfo") as TodoInfo
SpeedyLog.i("yulu", "action = ${intent.action}")
when (intent.action) {
TODO_CHANGE_ACTION -> {
block.invoke(todoInfo)
}
TODO_ALREADY_KNOW_ACTION -> {
block2.invoke(todoInfo)
}
}
}
}
}
5、效果图展示
总结
以上就是定时消息提醒的实现方法,文章若出现错误,欢迎各位批评指正,文章乃原创,转载请注明出处谢谢❤。