How to schedule notifications using WorkManager?
Asked Answered
C

5

21

I want to schedule a notification everytime the user add a note in the database for a specific time. While there are multiple ways to do it using AlarmManager, BroadcastReceiver etc. How can it be done using WorkManager?

Charlot answered 11/5, 2018 at 20:27 Comment(0)
G
18

WorkManager isn't appropriate for work that needs to happen at a particular time.

You should use AlarmManager, and specifically AlarmManagerCompat.setExactAndAllowWhileIdle(), to get a callback at a specific time.

Gobert answered 13/5, 2018 at 0:39 Comment(11)
Is it because due to this limitation? For every alarm, we have a unique tag for WorkManager. However, sometimes, we get unexplained exception caused by WorkManager - ` java.lang.IllegalStateException: Apps may not schedule more than 100 distinct jobs`Infeld
@ShuwnYuanTee - that's a known issue, already marked as fixed for alpha03. You still shouldn't be scheduling hundreds of different jobs at different times in the future though.Gobert
"You still shouldn't be scheduling hundreds of different jobs at different times in the future though. " -> Thanks. May I know the reason for such advice? The reason we are reluctant to use AlarmManager is that, it doesn't have "TAG" concept. It is rather difficult to cancel a already scheduled alarm. (Different pending intent, with different extras, are treated as same) In contrast, WorkManager has TAG concept. Hence, it is rather convenient for us to cancel an already scheduled alarm.Infeld
@ShuwnYuanTee - a common tactic is to only schedule one alarm (the next one) and have it schedule the next alarm when it fires. Absolutely no reason to have the system keep track of a ton of alarms if you know they'll fire sequentiallyGobert
Thanks for advice. However, such tactic does have shortcoming. Missing one alarm (which I believe is quite common due to Doze feature), will cause sub sequent alarms not scheduled.Infeld
@Gobert So it should be understood that the Android SDK as of now does not have a clear way to programmatically schedule repeating tasks at pecific time intervals.Tilbury
Alarms are not triggered in few OEMs , is there any other way ?.Occupancy
@Gobert AlarmManager doesn't seem to work in Android pie :(Bald
I think this answer is outdatedSafar
@JemshitIskenderov - nope, WorkManager absolutely is not the right API for running something at a particular time - WorkManager does no work while the device is dozing, which breaks any semblance of exact timing (since the device can be dozing at any time, your app can't control that part)Gobert
on the other hand AlarmManager loses everything on device boot, it needs local storage assistanceSafar
R
6

You can show notification with the help of workmanager. Workmanger can be used for scheduling single occurrence task or periodic occurrence task as well as we can schedule task at a particular time.

OneTimeWorkRequest request= new OneTimeWorkRequest.Builder(CustomWorkerClass.class)
.setInitialDelay(delayedTime, TimeUnit.MILLISECONDS)
.addTag("TAG")
.build();

'delayedTime' -> calculate time when to trigger notification

for more implementation details click here. To read more regarding workmanager click here

Riding answered 16/4, 2019 at 10:45 Comment(2)
remember delayedTime is a variable where your wanted notification time substract by your current time.Mabe
It is not a good answer because WorkManager is not suitable for conditions that needs to be precise at exact time.Litch
A
2

According to the Android official documentation about worker manager: "These APIs let you create a task and hand it off to WorkManager to run immediately or at an appropriate time". In my app, I set a work to be activated 20 seconds after:

 // Schedule the time
 val request= OneTimeWorkRequestBuilder<YourWork>().setInitialDelay(20, TimeUnit.SECONDS).build()
    WorkManager.getInstance().enqueue(request)
Artful answered 23/5, 2018 at 21:56 Comment(1)
Yes, the app is opened when the alarm is fired. This doesn't mean that the app become in foreground when the alarm is fired, this means that the app is opened to run the code of the Worker and then it is closed. The lifecycle of an Android Application is OnCreate, EnterForeground, enterBackground and onTerminate. In this case, the app jumps beteween onCreate and onTerminate.Artful
R
2

It is not a good practice to do this kind of task using work manager when you want to trigger notification at particular time because work manager works for delay and async task that manage periodic or delay functionality.Still you can do this using this method which is not a good practice,

You can get calendar values like this,

val timePicker = your timepicker here
val calendar: Calendar = Calendar.getInstance()
val nowMillis = calendar.timeInMillis

and then you can set your worker for specific task as below,

calendar.set(calendar.get(Calendar.YEAR),
         calendar.get(Calendar.MONTH),
         calendar.get(Calendar.DAY_OF_MONTH),
         timePicker.hour,
         timePicker.minute)
val difference = calendar.timeInMillis - nowMillis
val alarmRequest = OneTimeWorkRequest
            .Builder(AlarmWorker::class.java)
            .setInitialDelay(difference, TimeUnit.MILLISECONDS).build()
WorkManager.getInstance(this).enqueue(alarmRequest)
Roanne answered 15/11, 2021 at 6:47 Comment(1)
I'm curious to know what happens if the difference is a negative value. Fore example, we have setInitialDelay(-10000, TimeUnit.MILLISECONDS)Epagoge
F
1

As ianhanniballake stated

WorkManager isn't appropriate for work that needs to happen at a particular time.

But this can be set in near future of the exact time, depending on the state of the battery optimization.

An workaround will be like:

// Time to show notification at
LocalDateTime timeAt = LocalDate.now().atTime(20, 0);
LocalDateTime timeNow = LocalDateTime.now();

OneTimeWorkRequest.Builder workBuilder = new OneTimeWorkRequest.Builder(NotificationWorker.class);
// I just need to set an delay here
workBuilder.setInitialDelay(Duration.between(timeNow, timeAt));

// This is just to complete the example
WorkManager.getInstance().enqueueUniqueWork(UNIQUE_WORK_SHOW_NOTIFICATION,
                                    ExistingWorkPolicy.REPLACE,
                                    workBuilder.build());
Flexuosity answered 19/2, 2019 at 13:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.