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.
Related
I want to show notification at certain time and day by using retrofit2 networking.
But in alarm manager doc. It mentioned that isn't proper fpr networkong job. But in workmanager doc it says for the exact time job use alarm manager. What would be better for me to use? Alarm manager nor work manager
Android has introduced so many things that need to save battery life like:
Doze version 1 - API 6.0
Doze version 2 - API 7.0
https://developer.android.com/about/versions/nougat/android-7.0-changes#perf
Removing CONNECTIVITY_CHANGE Manifest declaration and others in - API 7.0
https://developer.android.com/guide/components/broadcasts
Background execution limitations in API 8.0
https://developer.android.com/about/versions/oreo/background#services
App Standby Buckets API 9.0 (Upgraded in Android 12)
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 Saver improvements in API 9.0
https://developer.android.com/about/versions/pie/power#battery-saver
https://developer.android.com/topic/performance/power/power-details
App Hibernation in 11 and 12 API.
All this stuff were not done for us to be able to do whatever we want by using the WorkManager. WorkManager was created to integrate all this requirements in a single API.
That is why the idea behind it is:
do some work
finish it at some point for sure(even if the device is restarted)
SAVE THE BATTERY AND NETWORK USAGE BY COMPLYING WITH THE ABOVE
Before that you had the AlarmManager to wake up in exact time
Services to keep the app process alive by giving your application priority. You still have them with the exclusion that now the starting services in the background are problematic. As per:
https://developer.android.com/about/versions/oreo/background#services
So if you want to do things like this you need to fully understand the Android API and limitations.
If you need help in StackOverflow - you need to fully understand your use case, you should have really put your mind into trying to understand it, communicate all these limitations with your PMs and explain to them that the Android Ecosystem is pretty complicated, there are a lot more applications besides the one you are writing and they all compete for resources. We can't do everything that we want. It is highly unlikely for the user itself to want to do long-running operations in exact timing starting from the background. But it might need it. Also, you have the option to ask to be exempted from battery optimization:
https://developer.android.com/training/monitoring-device-state/doze-standby#support_for_other_use_cases
Also, some people try to use Push notifications, but it is highly unlikely that it will work in your case. You can send high-priority ones, but if android detects that the user is not interacting with the notification they will lose its priority. And if you do not have the priority and also want to do a long-running operation - you need to create... a Work in the WorkManager :)
But long story short:
what will wake you up:
AlarmManager is exact
WorkManager is not
what will keep you alive:
Service
WorkManager(it uses its own service)
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
I am recording output from a accelerometer.
Can anyone recommend a reliable way to monitor onSensorChanged after the app has been closed (running the app in the background).
WorkManager
I have experimented with WorkManager. WorkManager appears to run only when the app is open. I read that this may be device specific as some devices force stop the app on close or otherwise prevent background tasks from executing once the app is closed.
sticky-notifications
I am curious about using sticky-notifications, although this would not be my first choice. I am now researching this option. I have noticed a few apps which implement this option. The downside is the sticky-notification can be viewed as annoying and the user may disable sticky-notifications.
Other options?
You should use a service if you want to run in the background. But probably the Android won't allow it because keep listening to a sensor in the background will consume too much battery. Mainly on Android P that is more rigorous with battery consumption.
WorkManager is not the right solution in this case as a Worker has an execution limit of 10 minutes, then it's stopped by the OS. But, time limit aside, WorkManager has been developed for other use case, so using for something like this (using some hack to reschedule a worker when you're close to the 10 minutes limit) seems a fight against the library design. To have an introduction behind the use cases that WorkManager is designed to solve you can take a look at this blog: Introducing WorkManager.
A Foreground service is an option, but I'm afraid that continuously monitoring the sensor can have a very bad impact on the battery life of the device. For more information on the available options, to run code in the background, your can check this blog: Modern background execution in Android
An alternative, depending on what you need to do with the sensor data, is to use the Activity Recognition API:
You can tell the API how to deliver results by using a PendingIntent, which removes the need to have a service constantly running in the background for activity detection purposes. Your app receives the corresponding Intents from the API, extracts the detected activities, and decides if it should take an action.
March 2021 Update
There have been a couple of updates since I originally wrote this answer:
WorkManager v2.3.0 introduced support for longer Workers with the option to "promote" them to Foreground Services using setForeground() for CoroutineWorkers and ['setGoregroundAsync()][5] for all kind of Worker`s. This is allows to overcome the 10 minutes limit and is documented in Support for long-running workers.
Android 12 is planning to introduce some changes to Foreground Services and this has some impact on WorkManager. The new v2.7.0, currently in alpha, is adding the concept of expedite work to provide support for Android 12 in a backward compatible way.
Overall, I still think that having your app monitoring the sensors while in background is going to have a bad impact on the battery of the device and you should look for alternatives.
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.
Previously one could assure a series of updates using an IntentService or SyncAdapter w/ a WakeLock.
Now with the new Doze mode, and limitations to save battery, is WakeLock still reliable enough, or should longer processes be started in the IntentService or SyncAdapter using WorkManager?
Also is WorkManager api production-ready?
As far as I understand it, the WorkManager can replace IntentService and SyncAdapter completely. E.g. everything you're doing in SyncAdapter.onPerformSync() can now be in WorkManager.doWork().
It got a stable release 2.4.0 and is ready for production.
Regarding wake locks: In Android 8.0 there is the following change:
As one of the changes that Android 8.0 (API level 26) introduces to improve battery life, when your app enters the cached state, with no active components, the system releases any wakelocks that the app holds.
So I wouldn't rely on wake locks anymore. I think they will be completely removed in future Android versions. And most of the time you don't need them with the WorkManager.
I wouldn't bother using JobScheduler or AlarmManager. WorkManager sits on top of these, and handles everything for you, doesn't matter what android version your app runs on.
https://codelabs.developers.google.com/codelabs/android-workmanager
Here's a good example about WorkManager, where they use a Worker for image processing, but it's perfectly good to do any long-running tasks.
You can specify constraints on various things, including if you want the device to be idle to run the worker. You can also chain the workers, pass data from one to other, even group them and run some parallel, wait for all to finish and then continue with another (or more) worker(s).
Depending on your use case, you can basically start a worker from anywhere (activity, broadcast receiver, stc).
In fact I use workers started from a broadcast receiver to do some api calls, only when you have internet connection of course (settable constraint) and it's so easy to set up and works so well, I only can recommend it to use (and bless Google for finally making these AC libraries).
I also really like the fact that the WorkManager saves works to db with room, so it can pick it up whenever all the conditions check out, even if you restart the device between. If you have some monitoring set up (like for example stetho), you can actually see how it saves the jobs to its own database.
It's still in alpha, but it's so solidly built, I don't think they'll change too much until they release the final version.