No Delay in reciving Notification for Task Expiration in Android To-Do List App Project

Dev@C2004

New member
Jul 15, 2023
2
3
3
Visit site
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 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 : The 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 of adding the task , like if its expiration time is very far away, still showing 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.