[Android Q&A, Help & Troubleshooting] ChayanDev:
**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.