WorkManager setRequiresDeviceIdle is confusing - android

I have implemented a scheduled work manager. My idea is to complete a process every 2 hours. But I need guaranteed execution. According to Work Manager's documentation every enqueued process will be executed guaranteed.
But now this setRequiresDeviceIdle is getting me confuse. It is stated in the documentation that by default setRequiresDeviceIdle has set to false. So what I assumed is that my process will not work if the device is in idle mode.
And Idle mode = When the phone is screen off for some interval.
But If I set this setRequiresDeviceIdle to true. I assume that now it will only work when device is in idle mode.
I want process to be complete even device is in idle or not in idle. What should I do now?

If you go through the WorkManager Docs, you will find:
requiresDeviceIdle boolean: true if device must be idle for the work to run
If you pass true, it means that your work will be executed only when device is in idle state.
As you mentione you want your task to be executed always. Hence, you should pass false in setRequiresDeviceIdle().
Note: It's not necessary that your task will execute exactly after 2 hours. According to the DOCS, your task might be deferred till next maintenance window. You task would be executed for sure, but the duration won't be exactly 2hrs. It might be a little more than that.
In Doze mode, the system attempts to conserve battery by restricting apps' access to network and CPU-intensive services. It also prevents apps from accessing the network and defers their jobs, syncs, and standard alarms.
Periodically, the system exits Doze for a brief time to let apps complete their deferred activities. During this maintenance window, the system runs all pending syncs, jobs, and alarms, and lets apps access the network.
If you wan't your task to be always executed and at exact time, you can use Alarm Manager and setExactAndAllowWhileIdle(). But this practice is discouraged, as it is not good for battery performance.

Related

Alarm Manager or Work Manager for Recurring Background Work

I'm having trouble deciding whether to run some recurring background work with Alarm Manager or Work Manager:
The work is going to consist of Room Database operations so I'll need access to Dao to complete my work.
It is going to be recurring at fixed intervals (hourly, daily, weekly, monthly, etc.)
I need to set a start date and time for the recurrence intervals.
the work will recur until canceled by the user
If the user is using the app when the work is supposed to be scheduled, I want the work to be done immediately. If the user is not on the app (app is in the background or device is turned off), I don't care if the work is done after the scheduled time as long as it is at least started by the next time the user opens the app.
the work needs to continue as scheduled after device reboots and app restarts.
For recurring background work, AlarmManger isn't suitable. As the name implies, it's intended to notify the system of an event at a precise time. Just like a physical alarm that wakes a person up even if the person sleeps, AlarmManager will wake up the device from doze mode which will result in more power usage. it is suitable for suitations like setting remainders such as for calender events which the users probably set by themselves.
On the other hand, WorkManager is intended to carry out background processing or work that would persist. Workmanager is much more efficient for recurring task especially as it allows you set constraints to determine when it should start or stop the background work.
check the link form the offical documentation on WorkManger:
workmanager architecture
tabular comparison between the two
It mostly depends on how important your task is.
https://developer.android.com/guide/background is a really good entry point to help you choose what you should work with.
WorkManager is the modern, universal approach of handling background work and it fits for most use-cases, it automatically reschedules work after a device restart or an application crash, and it is very efficient in terms of battery usage.
As WorkManager does respect Android's doze mode, it does not guarantee, that the work will be done exactly on time, though it does guarantee, that your work will be done within a certain time frame.
On the other hand, AlarmManager is capable of running work precisely on time. But this means that the device will wake up when your work scheduled with AlarmManager is coming due. This will drain battery and your app will probably show up as battery-draining in the Device Health board.
But as stated in the article above, prefer using WorkManager if possible. AlarmManager should only be used for e.g. a time-sensitive calendar notification.

Is it possible to run an Android Periodic and Onetime workers during Doze Mode or App Standby?

I have an app that uses both periodic and onetime workers to perform various tasks, some of which require a network connection. My client reported to me that a certain required daily task was not performed on a day he did not use the app at all. Despite the app's not having been run on a given day, the workers still need to run in order to report various statistics to the backend server. I assume this is due to the fact that the app was in App Standby Mode for the entire day, as well as the device's being in Doze Mode for at least part of the day. So my question is, is it possible to make a periodic or onetime worker run while the app is in App Standby or Doze Mode, or will it always be delayed until the device and/or app wakes up?
Alternatively, would I be better off using alarms instead of workers? I see that it is possible to set an alarm using setExactAndAllowWhileIdle() that "will be allowed to execute even when the system is in low-power idle modes." Does "idle mode" imply Doze and/or App standby mode?
I have been grappling with this for a while now, so any help and/or guidance is greatly appreciated.
Work Manager is Deferrable background work when the
work’s constraints are satisfied. if all the constraints set on a WorkRequest are
satisfied, Work can still be run with some additional delay. It's because WorkManager respecting Android battery optimization strategies. Also, you can read more about WorkManager constraint to understanding the work's constraint here:
https://developer.android.com/reference/androidx/work/Constraints.Builder.html

Perform critical un-deferrable work in a system application service

I am working with a system application. It has to perform some extremely critical tasks in a service that are triggered by broadcasts from the system.
Due to the background execution limits introduced in Oreo, I've been thinking a lot about how to perform the tasks in the background.
The tasks have the following requirements:
They may not be deferred, they have to be started instantly.
They shall be started even if the phone is idle (or dozing, I haven't really understood the difference)
They are highly critical. They shall complete after being started, under all circumstances.
I looked into using IntentService. But, they recommend using JobIntentService instead due to the background execution restrictions. However, this doesn't comply with my requirement of not deferring the work. It also says that JobScheduler does not run during doze. When running on O or later, JobIntentService will perform the task as a JobService Job:
When running as a Job, it will be subject to standard JobScheduler policies for a Job with a setOverrideDeadline(long) of 0: the job will not run while the device is dozing, it may get delayed more than a service if the device is under strong memory pressure with lots of demand to run jobs.
It seems like using a regular IntentService may expose the tasks to the possibility to be stopped/killed by the system under certain circumstances, imposed by the new restrictions from Oreo and above.
The safest option seems to be to launch a foreground service. But, I don't necessarily want to show a notification during the service's lifetime. Also, I believe that if the user accidentally disables the notification channel in the settings, the service cannot be started anymore. I'm also worried about edge cases where the system may arbitrarily kill or stop my service, or simply stop my work in some other way by not honoring my wake lock etc.
I recently came across the android:persistent in the application tag in the manifest. It says it can only be used by system applications. According to this blog post from 2011 setting this attribute to true renders your application and it's services un-killable. It also implies that it can let you have a background service that is "always alive". But how does this relate to doze, battery optimizations etc? Do I still have to acquire a wake lock and whitelist my app from battery optimizations in order to continue performing the background work during doze conditions?
Thanks a lot for reading and I hope you have some valuable input. I am currently a bit confused, trying to put all the pieces together. It doesn't help that the documentation is (as per usual)... lacking.

How to schedule a job using JobScheduler only when device is not in doze (not even Maintenance window)?

The JobInfo.Builder has a method for setting device idle state but i am confused as to what it is exactly trying to say.
setRequiresDeviceIdle (boolean requiresDeviceIdle)
Specify that to run, the job needs the device to be in idle mode. This defaults to false.
Idle mode is a loose definition provided by the system, which means that the device is not in use,
and has not been in use for some time. As such, it is a good time to perform resource heavy jobs.
Bear in mind that battery usage will still be attributed to your application, and surfaced to the user in battery stats.
Now the description for the boolean is as follows:
requiresDeviceIdle boolean: Whether or not the device need be within an idle maintenance window.
I basically need the job to fire when the device is not dozing, preferably not even in the maintenance window. The purpose of the job is to download stuff from a network.
Will setting it false cause it to run when the device is not in the maintenance window? ( the actual deep sleep state IDLE and the running state)
will setting it to true cause it to run only in the maintenance windows and in no other cases?
Setting setRequiresDeviceIdle(true) will run the scheduled job in the maintenance window of device dozing.
A Maintenance window is a period of dozing(idle state) where all accumulated jobs are given a chance to run for a specific period of time and then the device goes to doze again and then after some time the maintenance window time started and the cycle will be repeated. So when you set true to setRequiresDeviceIdle() you job will be executed only in those maintenance windows.
So if you want your job to run at any time(even when the user is using the device) then set setRequiresDeviceIdle() to false

Android - JobScheduler or BroadcastReceiver?

In my Android app I need to do some work every time the user plugs their device. For this purpose right now I use a BroadcastReceiver, which starts my IntentService to do the work when the user plugs the device and stops it when the device becomes unplugged.
Right now I'm thinking of using JobScheduler for Android 5.0+, but what I'm seeing is that with JobScheduler, I would have to schedule my job within the app, by calling
JobScheduler.schedule(JobInfo);
But this is a problem to me, because I want my job to run every time the user connects their device to the charger, even without the user having to open my app.
For this reason, I think one way would be to schedule it the first time the user opens the app, and then always force reschedule, since I cannot trust on the user opening my app every day (which, due to the nature of my app, certainly won't happen).
So, should I stick with BroadcastReceiver or use JobScheduler for Android 5.0+?
And in the case of using JobScheduler, should I schedule my job only once and then always return true in order to force rescheduling?
Thank you.
So, should I stick with BroadcastReceiver or use JobScheduler for Android 5.0+?
Use JobScheduler, this can improve your app’s performance, along with aspects of system health such as battery life. Also, JobScheduler persists through device reboots and supports batch scheduling by which the android system can combine pending jobs thus reducing battery usage. Moreover, you can do distinguish between android versions thus using JobScheduler on Lollipop and up, and AlarmManager on older versions.
And in the case of using JobScheduler, should I schedule my job only once and then always return true in order to force rescheduling?
Now, there are 2 ways to do this :
As you guessed, scheduling your job only once and always returning true in jobFinished() - this should do the trick.
Upon completing a job (originally scheduled by you by calling JobScheduler.schedule(JobInfo)), you schedule another job by calling the same. This will schedule consequent jobs once each job is about to be completed.
Jobscheduler runs in the background and persists through reboots so you should be fine.

Categories

Resources