Android PeriodicWorkRequest. Which time it will execute? - android

I created a periodic weekly work manager worker to delete the files my application creates.
WorkManager workManager = WorkManager.getInstance(context);
workManager.cancelAllWorkByTag(workTag);
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(DeleteFileWorker.class, 7, TimeUnit.DAYS).addTag(workTag).build();
workManager.enqueueUniquePeriodicWork(workTag, ExistingPeriodicWorkPolicy.REPLACE, periodicWorkRequest);
Here, I'm telling the worker to run once a week or once each 7 days.
But when is it going to run? Can I control the approximate hour?
My guess is it will run the first time it can when the application starts and the second time will be at the same hour(approximately) and day as the first launch.
Can I configure it to run around 12 AM? It doesn't need to be an exact time.

You can't have strong expectations with WM. Please check here the Constraints section:
https://developer.android.com/topic/libraries/architecture/workmanager/how-to/debugging#use-alb-shell0dumpsys-jobscheduler
Also, let me point one thing - what you have "is not" a periodic Work.
What WM does is that it creates a single job in the JobScheduler and it has an extra Constrain - TIMING_DELAY. At the same time besides explicit constraints, you have implicit ones coming from the system. So for a work to be executed all the right conditions need to be in places related to battery optimizations, doze, power buckets, etc. So you can't say for sure when it will happen.
And when the work is executed successfully - WM creates a new job in the JS with TIMING_DELAY again the time you see as a period. So if you put 24 hours as a "period", but the conditions are not right for your work to be executed and it is delayed 10 hours - you will have a 34 hours span between 2 works.
Also, you know it is Android - on every device it is different. But you can improve this by asking your application to be excluded from battery optimization.
https://developer.android.com/training/monitoring-device-state/doze-standby#support_for_other_use_cases
Here more on what to expect from each device:
https://dontkillmyapp.com/
Also, have it in mind that you have a specific amount of time depending on your power bucket to run per day. I guess you are not using Network, but if you do - there is also a set amount of time to use the network. Without battery optimization disabled you might hit some of these:
https://developer.android.com/topic/performance/power/power-details

Related

When the android app is force stopped and reopened, will WorkManager executes overdue work or startover?

Assume there is a scheduled work like this:
PeriodicWorkRequestBuilder<RefreshAuthWorker>(
repeatInterval = 15L,
repeatIntervalTimeUnit = TimeUnit.MINUTES,
flexTimeInterval = 5L,
flexTimeIntervalUnit = TimeUnit.MINUTES
)
Let's say, At 10th minute, I forcely killed/stopped the app.
Then reopen the app again after 10 mins.
by this time, the existing/killed work is overdue by 5 mins.
Now, What will the WorkManager do?
1.WorkManager respects the missed overdue work and do it immediately and then schedule the next work.
(or)
2.WorkManager ignores the past overdue work and schedules the next work?
This is a very important scenario to me because, let's say I have to refresh a token every 15 mins. But if WorkManager does like said in 1st point then, by the time I reopen the app, the token is already expired 5 mins ago and the next work is going to happen in 15 mins. So, it's a total of 20 mins with an expired token.
Can somebody who knows any idea what will the WorkManager do in such scenario, please help.
You can't do such things with a WorkManager.
Everything might happen if an application is forced stop. It is a problem of the user if he decides to do so. You should not care.
Are you sure you do not mean - clear from recent?
The priority of WM is saving resources like battery and network data. Timing is not a big concern. The idea is that you need some work to be executed for sure at some point. Like you want to upload a picture to a server.
What WorkManager does is - it creates a job in the JobScheduler. The job is executed when all the constraints are satisfied:
You have implicit constraints related to battery saving. You have some amount of resources that you can use based on your Power Bucket level. Also, the device's state is important. You can't predict when these constraints will be satisfied.
Also you have explicit constraints that you set. Like Connectivity, Battery level and in your case: "a period". But is a no period at all. When you have a "period" work on a higher level in the WorkManager - actually it means - many single jobs in the Job Scheduler. And each one of these jobs has the above implicit constraints and your explicit which is called - timing delay. So you see:
You start the work
WM schedules a job in JS with respective constraints
After 15min timing delay is satisfied
No one can tell what is the status of the implicit constraints. The device might be dozing, or you might have used all of your data usage for the last 24 hours or something like this.
5 At some point when all the constraints are satisfied - the Work starts and when it is finished:
6. You have a new job with the same constraints as before. So in theory your "15min period work" might be executed in 24 hours and after that, it might execute the second time in 15 minutes.

Android recommended and reliable API for periodic background work?

I've been using WorkManager to create notifications for my app. For my purposes I figured PeriodicWorkRequest is the most fitting, but after a bit of testing and reading online it's seems extremely unreliable. Using the minimal interval (15 minutes), and the app being closed, the worker woke up 5-6 times and then seems to be killed.
So how does one go about creating background work that wakes up in reasonable time intervals? What is the best approach for creating event-based notification? My idea was checking for the event (for example, checking for something new in the database) in small time intervals (with 15 minutes also being less than ideal), but seeing as it doesn't work well with PeriodicWorkRequest and is also the recommended approach as per the documentation, what exactly are my options?
Basically, the idea of Android is for you not to be able to do what you want to do because we as developers try to kill the battery.
You need to see how the evolution of the restrictions goes:
Version 6 - Doze:
https://developer.android.com/training/monitoring-device-state/doze-standby
https://developer.android.com/about/versions/marshmallow/android-6.0-changes#behavior-power
Version 7 Another state of Doze with even more restrictions:
https://developer.android.com/about/versions/nougat/android-7.0-changes#perf
Broadcast Restrictions:
https://developer.android.com/guide/components/broadcasts
https://developer.android.com/about/versions/nougat/android-7.0-changes#bg-opt
Version 8.0 Background execution limits:
https://developer.android.com/about/versions/oreo/background#services
Version 9 StandBy Buckets - where depending on how the app is used you have different resources to use - like time to wake up the app, time to use the Network, etc
https://developer.android.com/about/versions/pie/power#buckets
https://developer.android.com/about/versions/12/behavior-changes-all#restrictive-app-standby-bucket
https://developer.android.com/topic/performance/appstandby
Battery Save improvements:
https://developer.android.com/about/versions/pie/power#battery-saver
Power Management Restrictions - really important.
https://developer.android.com/topic/performance/power/power-details
Version 11 and 12 App hibernation
https://developer.android.com/topic/performance/app-hibernation
Long story short - you need to prevent all these restrictions to harm your work. But you need to comply because it is better for the user.
But there is no API that will just say - "f**k all these restrictions and do whatever the dev wants to do."
If you need exact timing - you need AlarmManager.
If you do not know when you need to do your work and depend on the outside - Push Notifications which then can transfer the work to the WorkManager.
If you need periodic work that is not time-critical - you might not use the AlarmMangaer and be sure that the work is finished, but you can't be sure when, because there are many restrictions and the priority will be saving the resources.
Also, you can ask the user to be exempted from Battery Optimization:
https://developer.android.com/training/monitoring-device-state/doze-standby#support_for_other_use_cases
If you want to know why exactly the work is not executed you need to check the JS dump and see what restriction is not satisfied:
https://developer.android.com/topic/libraries/architecture/workmanager/how-to/debugging#use-alb-shell0dumpsys-jobscheduler

Execute task every hours at specific milliseconds Android

For my app I need to execute a task every hours but at specific time.
A server return to me a number of millisecond for example : 100ms, so I need to execute a task at :
00:00:00.100
01:00:00.100
02:00:00.100 etc ....
If the number is 3500 for example, I need to execute task at :
00:00:03.500
01:00:03.500
02:00:03.500 etc ...
I know how to run a task every 1 hour with an interval but I don't know how to do it at a specific time. If anyone has a solution :)
If you really need the exact ms (and I really, REALLY doubt that you do) you're out of luck. Android isn't a real time OS, because Linux isn't a real time OS, and doesn't make those assurances. If you just need really close to the time (like exact to the second), AlarmManager.setExactAndAllowWhileIdle will be called even in low power mode. However there is no repeating version of that, so you'll need to implement that yourself if needed. And AlarmManager doesn't persist alarms through reboot, so if you need it you'll have to do that. Finally you have about 10s to execute whatever you need or take appropriate measures like wake locks to do more.
This also requires the schedule exact alarm permission. Read the docs at https://developer.android.com/reference/android/app/AlarmManager#setExactAndAllowWhileIdle(int,%20long,%20android.app.PendingIntent)

Workmanager OneTimeWorkRequestBuilder not working with long duration in setInitialDelay

i am using Workmanager to perform an action every midnight , i am using it like that :
val duration = midNight.time - now.time
val workRequest =
OneTimeWorkRequestBuilder<ActionWorker>()
.setInitialDelay(duration, TimeUnit.MILLISECONDS)
.build()
WorkManager.getInstance(context)
.enqueueUniqueWork(
WORKER_ID,
ExistingWorkPolicy.REPLACE,
workRequest
)
and inside the ActionWorker doWork i write to the sharedpreferences, the problem is when duration is relatively short time like 2 to 5 hours ,action is performed perfectly, otherwise if the duration is set to 12 hours for example, the action is not performed .
i set duration to half an hour and i tried killing the process using
adb shell am kill "package name"
and the task is still performed well after half an hour, does anybody have an idea why it get lost when it is set to long duration ?
"not working for long durations" is not your problem. Try to debug the job scheduler. As WorkManager uses jobs underneath:
https://developer.android.com/topic/libraries/architecture/workmanager/how-to/debugging
Execute:
adb shell dumpsys jobscheduler
And check:
Unsatisfied constraints: TIMING_DELAY CONNECTIVITY [0x90000000]
If TIMING_DELAY is satisfied, and I am sure it will be - there might be other reasons why the Work is not executed. There are a lot of restrictions from Android like how many times a work can be executed per 24 hours or how much Network usage you are allowed. Check here:
https://developer.android.com/topic/performance/power/power-details
Are you also sure what you want to achieve? Why every night? Check:
https://developer.android.com/reference/androidx/work/Constraints.Builder
In general, the idea is for you to pick the conditions - idle/not idle device, Wi-Fi/no Wi-Fi, charging/not charging, low battery/not low battery, and then Android will decide when to execute. If there is something related to the server-side requirements I would get it. But otherwise, I don't.
And then you set the requirements, put a periodic job with a period of 24 hours and some flex period of 2-3 hours and you are done.
EDITED:
How to debug TIMING_DELAY problems:
check the following fields in the job info:
Minimum latency: +19m59s941ms
Enqueue time: -1m47s251ms
Run time:earliest=+18m12s690ms, latest=none, original latest=none
That is how you can see when the work was scheduled, what delay is set and when you should expect the TIMING_DELAY to be satisfied. If it is not what you expected - check again what you have set or check if you are now in the case of failing and retrying works. If it is retrying the minimum latency comes not from what you have set for a period/delay, but from the policy settings. More on this here:
https://developer.android.com/topic/libraries/architecture/workmanager/how-to/define-work#retries_backoff
Also, you should have in mind that the lifecycle of the Work is bigger than the one of the job. One Work can create and trash many jobs. You have a job for a single work. The work fails and needs to retry - a new job is scheduled. You can observe this more easily via:
Background Task Inspector
https://developer.android.com/studio/inspect/task
Here you can see the number of retries, etc.

Android JobScheduler bug: delay is increased after reboot (param minimumLatency)

I am working with Android JobScheduler, using a JobInfo.Builder() to launch my Service at a specified time.
Everything works correctly, even when my device enters in sleepmode. But when I restart the device, all the jobs still exist but their delay has been increased, to an astonishing number.
I am creating jobs with specified delay (param minimumLatency) and using the param setPersisited(true) in order to keep the jobs after reboot.
For example let's say I set minimumLatency to 120_000ms.
If I don't reboot my task is correctly executed after the specified delay.
But if I reboot before the task, my mimimumLatency is increased to roughly 40 Billion milli
I have also tried to setOverrideDeadline() to various delays, it des not help
This is how I create the Job:
JobInfo.Builder(id, componentName)
.setExtras(bundle)
.setPersisted(true)
.setMinimumLatency(initialDelay)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.build()
.let {
context.getSystemService(JobScheduler::class.java). schedule(it)
}
Please let me know if you have a clue about this issue.
Any help will be appreciated.
Thanks
I found the issue and a way to solve it. Maybe this will help someone.
It is actually a bug.
When the device boots, in the logs I can see that the device's date is december 31st 2016.
And then, later on when the internet is connected, the system's date is updated to today's date.
So I figured my increased delay is the time between today and Dec. 31st 2016!
I think Android is Starting the JobScheduler service before setting up the date and thus setting them thinking it will be in 1 year and a half.
I guess it depends of the devices. I am on Android TV.
Anyway, this was obviously not directly solvable, so I implemented my own rescheduling in my service and I dont keep the persited parameter.
And doing it this way is actually better for my project and future required customizations.

Categories

Resources