Chayan
New Member
**Question:**
I want to set a notification for each item in my to-do list when it is about to expire in the next 5 minutes or before 5 minutes of the expiration time. However, in the current implementation, the notification is showing instantly after adding a task to the to-do list. How can I prevent this error?
*example : Current time is 6:00 pm expiration time is 6:30 pm , so the notification should appear at 6:25 pm even if the app is closed.*
But notification is Appearing at instant adding the task , like if its expiration time is very far still swoing notification expired.
Please Give Suggestions to fix this issue.
Here is My Impelementation Logic
**NotificationWroker Class**
package com.example.todolist
//imports
class NotificationWorker(
private val context: Context,
workerParams: WorkerParameters
) : Worker(context, workerParams) {
override fun doWork(): Result {
// Retrieve the task details from input data
val taskId = inputData.getLong("taskId", -1)
val taskName = inputData.getString("taskName")
val expirationTime = inputData.getString("expirationTime")
// Check if the app has the required permission to post notifications
if (ContextCompat.checkSelfPermission(
context,
Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
// Permission not granted, handle the situation (e.g., show a message or request permission)
// You can implement your own logic here based on your app's requirements
// For example, you can show a message to the user or request the permission
// using a dialog or an in-app prompt.
// Remember to handle the permission request response as well.
return Result.failure()
}
// Create the notification channel if it doesn't exist
createNotificationChannel()
// Create the notification
val notification = NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle("Task Expired")
.setContentText("Task '$taskName' has expired!")
.setSmallIcon(R.drawable.bar_icon)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.build()
// Show the notification
val notificationManager = NotificationManagerCompat.from(context)
notificationManager.notify(taskId.toInt(), notification)
return Result.success()
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID,
"Task Notifications",
NotificationManager.IMPORTANCE_HIGH
)
channel.description = "Channel for task notifications"
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
companion object {
private const val CHANNEL_ID = "task_notification_channel"
}
}
**MainActivity Code(Only the Required Portion)**
addSaveBtn.setOnClickListener {
//edit task
if (et_item.text.isNotEmpty()) {
id++
var taskName = et_item.text.toString()
var category = categorySelected
if (time_tv.text.isNotEmpty()) {
var time = time_tv.text.toString()
var format = SimpleDateFormat("E, MMM d, yyyy", Locale.getDefault())
var date = format.format(Date())
val todo = TodoData(
id,
taskName,
false,
time,
date,
category,
isExpired = false,
isNotified = false
)
CoroutineScope(Dispatchers.Main).launch {
withContext(Dispatchers.IO) {
todoDao.insert(todo)
}
//scheduleLing
scheduleNotification(id,taskName,time)
}
todoList.add(todo)
Log.i("Add", "$todo")
todoAdapter.notifyItemInserted(todoList.size)
bottomDialog.dismiss()
emptyImg = findViewById(R.id.imageView)
if (todoList.size == 0)
emptyImg.visibility = View.VISIBLE
else
emptyImg.visibility = View.INVISIBLE
} else {
val snackBar = Snackbar.make(
addTaskLl, "Please Select Due Time!",
Snackbar.LENGTH_LONG
).setAction("Action", null)
snackBar.setActionTextColor(Color.WHITE)
val snackBarView = snackBar.view
snackBarView.setBackgroundColor(Color.RED)
val textView =
snackBarView.findViewById(com.google.android.material.R.id.snackbar_text) as TextView
textView.setTextColor(Color.WHITE)
snackBar.show()
}
} else {
val snackBar = Snackbar.make(
addTaskLl, "Task item Can't be Empty!",
Snackbar.LENGTH_LONG
).setAction("Action", null)
snackBar.setActionTextColor(Color.WHITE)
val snackBarView = snackBar.view
snackBarView.setBackgroundColor(Color.RED)
val textView =
snackBarView.findViewById(com.google.android.material.R.id.snackbar_text) as TextView
textView.setTextColor(Color.WHITE)
snackBar.show()
}
}
// bottomDialog.setCancelable(false)
bottomDialog.setContentView(view)
bottomDialog.show()
}
}
**Scheduling Function (present in the MainActivity Class)**
private fun scheduleNotification(taskId: Long, taskName: String, expirationTime: String) {
val workManager = WorkManager.getInstance(applicationContext)
// Parse the expiration time string to a Date object
val format = SimpleDateFormat("hh:mm a", Locale.getDefault())
val expirationDate = format.parse(expirationTime)
// Calculate the delay before showing the notification (5 minutes)
val notificationDelay = 5 * 60 * 1000 // 5 minutes in milliseconds
// Calculate the expiration time in milliseconds
val expirationMillis = expirationDate?.time ?: return
// Calculate the notification time by subtracting the delay from the expiration time
val notificationTime = expirationMillis - notificationDelay
// Build the input data
val inputData = Data.Builder()
.putLong("taskId", taskId)
.putString("taskName", taskName)
.build()
// Create a OneTimeWorkRequest with input data and delay
val notificationWorkRequest = OneTimeWorkRequestBuilder<NotificationWorker>()
.setInputData(inputData)
.setInitialDelay(notificationTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS)
.build()
// Enqueue the work request with a unique tag
workManager.enqueueUniqueWork(
"notification_$taskId",
ExistingWorkPolicy.REPLACE,
notificationWorkRequest
)
}
Except those Two more Functions are Implemented in Adapter Class to Cancel the Notification for the item which is expired or deleted.
I want to set a notification for each item in my to-do list when it is about to expire in the next 5 minutes or before 5 minutes of the expiration time. However, in the current implementation, the notification is showing instantly after adding a task to the to-do list. How can I prevent this error?
*example : Current time is 6:00 pm expiration time is 6:30 pm , so the notification should appear at 6:25 pm even if the app is closed.*
But notification is Appearing at instant adding the task , like if its expiration time is very far still swoing notification expired.
Please Give Suggestions to fix this issue.
Here is My Impelementation Logic
**NotificationWroker Class**
package com.example.todolist
//imports
class NotificationWorker(
private val context: Context,
workerParams: WorkerParameters
) : Worker(context, workerParams) {
override fun doWork(): Result {
// Retrieve the task details from input data
val taskId = inputData.getLong("taskId", -1)
val taskName = inputData.getString("taskName")
val expirationTime = inputData.getString("expirationTime")
// Check if the app has the required permission to post notifications
if (ContextCompat.checkSelfPermission(
context,
Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
// Permission not granted, handle the situation (e.g., show a message or request permission)
// You can implement your own logic here based on your app's requirements
// For example, you can show a message to the user or request the permission
// using a dialog or an in-app prompt.
// Remember to handle the permission request response as well.
return Result.failure()
}
// Create the notification channel if it doesn't exist
createNotificationChannel()
// Create the notification
val notification = NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle("Task Expired")
.setContentText("Task '$taskName' has expired!")
.setSmallIcon(R.drawable.bar_icon)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.build()
// Show the notification
val notificationManager = NotificationManagerCompat.from(context)
notificationManager.notify(taskId.toInt(), notification)
return Result.success()
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID,
"Task Notifications",
NotificationManager.IMPORTANCE_HIGH
)
channel.description = "Channel for task notifications"
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
companion object {
private const val CHANNEL_ID = "task_notification_channel"
}
}
**MainActivity Code(Only the Required Portion)**
addSaveBtn.setOnClickListener {
//edit task
if (et_item.text.isNotEmpty()) {
id++
var taskName = et_item.text.toString()
var category = categorySelected
if (time_tv.text.isNotEmpty()) {
var time = time_tv.text.toString()
var format = SimpleDateFormat("E, MMM d, yyyy", Locale.getDefault())
var date = format.format(Date())
val todo = TodoData(
id,
taskName,
false,
time,
date,
category,
isExpired = false,
isNotified = false
)
CoroutineScope(Dispatchers.Main).launch {
withContext(Dispatchers.IO) {
todoDao.insert(todo)
}
//scheduleLing
scheduleNotification(id,taskName,time)
}
todoList.add(todo)
Log.i("Add", "$todo")
todoAdapter.notifyItemInserted(todoList.size)
bottomDialog.dismiss()
emptyImg = findViewById(R.id.imageView)
if (todoList.size == 0)
emptyImg.visibility = View.VISIBLE
else
emptyImg.visibility = View.INVISIBLE
} else {
val snackBar = Snackbar.make(
addTaskLl, "Please Select Due Time!",
Snackbar.LENGTH_LONG
).setAction("Action", null)
snackBar.setActionTextColor(Color.WHITE)
val snackBarView = snackBar.view
snackBarView.setBackgroundColor(Color.RED)
val textView =
snackBarView.findViewById(com.google.android.material.R.id.snackbar_text) as TextView
textView.setTextColor(Color.WHITE)
snackBar.show()
}
} else {
val snackBar = Snackbar.make(
addTaskLl, "Task item Can't be Empty!",
Snackbar.LENGTH_LONG
).setAction("Action", null)
snackBar.setActionTextColor(Color.WHITE)
val snackBarView = snackBar.view
snackBarView.setBackgroundColor(Color.RED)
val textView =
snackBarView.findViewById(com.google.android.material.R.id.snackbar_text) as TextView
textView.setTextColor(Color.WHITE)
snackBar.show()
}
}
// bottomDialog.setCancelable(false)
bottomDialog.setContentView(view)
bottomDialog.show()
}
}
**Scheduling Function (present in the MainActivity Class)**
private fun scheduleNotification(taskId: Long, taskName: String, expirationTime: String) {
val workManager = WorkManager.getInstance(applicationContext)
// Parse the expiration time string to a Date object
val format = SimpleDateFormat("hh:mm a", Locale.getDefault())
val expirationDate = format.parse(expirationTime)
// Calculate the delay before showing the notification (5 minutes)
val notificationDelay = 5 * 60 * 1000 // 5 minutes in milliseconds
// Calculate the expiration time in milliseconds
val expirationMillis = expirationDate?.time ?: return
// Calculate the notification time by subtracting the delay from the expiration time
val notificationTime = expirationMillis - notificationDelay
// Build the input data
val inputData = Data.Builder()
.putLong("taskId", taskId)
.putString("taskName", taskName)
.build()
// Create a OneTimeWorkRequest with input data and delay
val notificationWorkRequest = OneTimeWorkRequestBuilder<NotificationWorker>()
.setInputData(inputData)
.setInitialDelay(notificationTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS)
.build()
// Enqueue the work request with a unique tag
workManager.enqueueUniqueWork(
"notification_$taskId",
ExistingWorkPolicy.REPLACE,
notificationWorkRequest
)
}
Except those Two more Functions are Implemented in Adapter Class to Cancel the Notification for the item which is expired or deleted.