I have an app where I use a foreground service to start a number N of threads that sleep most of the time and sometimes wake up to do some measurements.
I used foreground services because I need that these measurements must be done at specific and exact time without background limitations introduced by Android 8.0.
This seems to work and from documentation seems that there are no problem, but I read also about JobScheduler.
There is an advantage to use Jobs to schedule work at specific accurate time or my solution can be used without problems.
First a fact
In JobScheduler, the System execute your Job(Task) in application's JobService
and the JobService class also extend the same Service class that we use to define Foreground Service. So by using the both, we can execute code in background
Now the main difference is, Foreground Service is always running(by showing notification to user) and consuming the battery and memory of the user even, if your threads are sleeping and no code is executing.
As it's running always you can do whatever you want precisely at any moment of time. maybe it's good for your app's point of view but it's bad for user. your app draining the battery unnecessarily and consuming the RAM.
To address this problem we got JobScheduler. you can Schedule a job to be executed based on some criteria. Your app will only wake when the criteria is met, but it's not precise.it depends on many factors like doze mode etc.
you can look more about that here
The conclusion is
If your task is not needed to be execute at exact time then you should use JobScheduler (recently WorkManager is better as it use JobScheduler internally and more advance) to save your user's battery
and according official document
WorkManager is intended for tasks that are deferrable—that is, not
required to run immediately—and required to run reliably even if the
app exits or the device restarts.
For your use case, you will be better off using a WorkManager which according to the android documentation, uses JobScheduler on API 23+ and a combination of BroadcastManager and AlarmManager on API 14 - 22.
With a WorkManager your jobs will run reliably even if your app exits or the device restarts.
https://developer.android.com/topic/libraries/architecture/workmanager
Related
Let's say I want to build an app which requests current location periodically (e.g., every 10 minutes, this number should be configurable) and submits to a server.
I'm aware that Foreground Service and WorkManager are normally suggested for this kind of scenario. However which is would suit more? Below are my thoughts and doubts.
WorkManager - is mainly for deferrable background work whose execution is guaranteed. However I know that from Android 8 (API 26) background location was introduced and that restrict location to be updated only a few times every hour https://developer.android.com/about/versions/oreo/background-location-limits. Thus this perhaps doesn't meet the periodical updates as per the requirement.
ForegroundService - is perfect for something that runs and needs to make users aware of. It's recommended for this kinda scenario (location tracking) for privacy purpose. Google also creates a sample app to promote this practice https://github.com/android/location-samples/tree/master/LocationUpdatesForegroundService.
From the above analysis, it seems ForegroundService is the one. However I also found that WorkManager has a built-in support to use Worker in conjunction with ForegroundService via androidx.work.impl.foreground.SystemForegroundService https://developer.android.com/topic/libraries/architecture/workmanager/advanced/long-running#long-running-kotlin
That makes me confused as to what should I use and what Google really recommend for this specific scenario.
Anyone has any idea?
If you want to communicate somehow with the service then use foreground service and if you want to have some processed input based on something else you did in that work manager then choose work manager.
Work manager doesn't have option to redeliver intents and all other commands like start sticky etc...
Since work manager is more suitable for syncing data with db, processing a file etc..
If you were to ask me, I'd choose foreground service since you can add a type location to the xml tag when you register it in the manifest.
Both of these solutions don't survive OEMs aggressive battery restrictions since WorkManager's work can be deferred and if I want instant execution combined with wake locks I can easily do it in the foreground service since it also has a binder option that works well for UI sync.
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.
I have a use-case where, whenever a transaction is completed or failed, I have to wait in background(not going to freeze the UI) for 5 minutes and call a piece of code without user intervention. So AFAIK I need to implement Background Service for this.
I want to know which would be better for my scenario.
Workermanager ( JetPack )
Jobscheduler ( for API 14 - 21, Firebase JobDispatcher)
IntentService
And in Oreo and above, if I run background service will it show in the notification that the App is running in the background?
Now the recommended way to do background processing would be Jetpack WorkManager API. I will cite official documentation for the reasons:
WorkManager chooses the appropriate way to run your task based on such factors as the device API level and the app state. If WorkManager executes one of your tasks while the app is running, WorkManager can run your task in a new thread in your app's process. If your app is not running, WorkManager chooses an appropriate way to schedule a background task--depending on the device API level and included dependencies, WorkManager might use JobScheduler, Firebase JobDispatcher, or AlarmManager. You don't need to write device logic to figure out what capabilities the device has and choose an appropriate API; instead, you can just hand your task off to WorkManager and let it choose the best option.
In addition, WorkManager provides several advanced features. For example, you can set up a chain of tasks; when one task finishes, WorkManager queues up the next task in the chain. You can also check a task's state and its return values by observing its LiveData; this can be useful if you want to show UI indicating your task's status.
So instead of worrying every time which background processing to choose (as every task has it's recommended and appropriate way), you can simply use WorkManager and it will do it's job.
This is considering the following gotcha:
WorkManager is intended for tasks that require a guarantee that the system will run them even if the app exits, like uploading app data to a server. It is not intended for in-process background work that can safely be terminated if the app process goes away; for situations like that, we recommend using ThreadPools.
P.S. As WorkManager API is using JobScheduler, Firebase JobDistpacher or AlarmManager under the hood, you must consider minimum API levels for used functionality. JobScheduler requires minimum API 21, Firebase JobDispatcher requires minimum API 14 and Google Play Services.
For the full documentation check: https://developer.android.com/topic/libraries/architecture/workmanager
For your second question: as far as I know you will always see that notification, as it is notifying user that your app is consuming battery. The notification may be disabled by the user from settings in Android Oreo 8.1.
Going forward, the official android documentation suggests that you use a JobScheduler in place of a background service.
In many cases, apps that previously registered for an implicit broadcast can get similar functionality by using a JobScheduler job. For example, a social photo app might need to perform cleanup on its data from time to time, and prefer to do this when the device is connected to a charger. Previously, the app registered a receiver for ACTION_POWER_CONNECTED in its manifest; when the app received that broadcast, it would check whether cleanup was necessary. To migrate to Android 8.0 or higher, the app removes that receiver from its manifest. Instead, the app schedules a cleanup job that runs when the device is idle and charging.
https://developer.android.com/about/versions/oreo/background#services
WorkManager is probably (eventually) the solution you are looking for. It acts as an abstraction, deciding whether to use JobScheduler (if it's available) Firebase JobDispatcher (if it's available) or falling back to a default implementation otherwise. This way, you get the best of all worlds. It's still in alpha, however, so you may want to at least consider other options.
If you choose not to use WorkManager, a combination of JobScheduler and JobDispatcher is probably appropriate (see here).
However, if you target devices without Google Play Services below API 22, you will need to use another solution. In that case AlarmManager may be what you are looking for, since you need a delayed task with guaranteed execution. Using an IntentService for this is possible, but not as easy. It involves introducing a delay mechanism of some kind, of which there are several choices.
Note that since you are using a batching mechanism if you use one of the Job APIs or WorkManager, you will not see a notification in Oreo. AlarmManager/IntentService based solutions may show a notification, but likely not for very long, since the tasks are fairly short. This is especially true for AlarmManager.
From Oreo, a service will not work if the app is not in foreground, but we can use JobSchedular to perform background operations.
Then what's really is the difference between JobScheduler and startService(), and why android is supporting JobSchedular over startService() for background operations from oreo.
I can still Schedule tons of Jobs from backround, and it will also effect battery performance.
From Oreo, a service will not work if the app is not in foreground
Yes, it will. It merely needs to be a foreground service.
Then what's really is the difference between JobScheduler and startService()
startService() is immediate. A job scheduled with JobScheduler is not. JobScheduler can postpone the work until a later time, when other work needs to be done, to minimize the amount of time that power is consumed (for CPU, for WiFi, for mobile data, etc.).
Also, startService() always happens. A job scheduled with JobScheduler might not. You can put criteria on the job (e.g., requires a network connection), and the job will only be run if the criteria are met.
and why android is supporting JobSchedular over startService() for background operations from oreo.
Power consumption, mostly, as far as I can tell.
I can still Schedule tons of Jobs from backround, and it will also effect battery performance.
Yes, but Google has a much better API for being able to control that in the future. If developers abuse JobScheduler, future versions of Android can further rate-limit jobs, expand Doze mode for jobs, and so on.
From Android developers website:
The framework will be intelligent about when it executes jobs, and
attempt to batch and defer them as much as possible. Typically if you
don't specify a deadline on a job, it can be run at any moment
depending on the current state of the JobScheduler's internal queue.
While a job is running, the system holds a wakelock on behalf of your
app. For this reason, you do not need to take any action to guarantee
that the device stays awake for the duration of the job.
When you start a background service it is running even if the app is in the background, thus it uses resources. With JobScheduler the resources are only allocated and used for a particular job, and are freed when it's done.
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.