Should a WorkManager be used with a SyncAdapter? - android

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.

Related

Foreground service vs WorkManager for location tracking

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.

Recommend a realiable way to continue running after the app is closed

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.

Best approach to achieve guaranteed repeating background work Android

I'm in the process of developing an app which would mainly just be doing background work to read data from a nearby BLE (Bluetooth Low Energy) sensor every 15 minutes (if Bluetooth is not switched on, it'll need to prompt the user to switch it on from the background service) and sync the data into the server once a day. I'm not sure of which approach would be most suited to do the background work as I need to have guaranteed timely execution of the background tasks as that's very critical to the purpose of the app.
I've looked at the following approaches:
Using a ServiceIntent instant with a WakefulBroadcastReceiver. But I found out that WakefulBroadcastReceiver has been deprecated and there has been more restrictions to run background work since Android O.
AlarmManager
JobScheduler
WorkManager (seems to be a good candidate but it's still in alpha and It doesn't seem to be production ready)
Any help will be much appreciated.
Thanks
My suggestion is to use WorkManager even in alpha. I am alredy use it for similar task and it works. First time i started to use it, there where crashes, but after new version become released no more crashes occurs. Google provide a good support to its library, so use WorkManager since its the best option for background tasks execution.

what is the best practice to use for background tasks?

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.

Android. Is WorkManager running when app is closed?

I want to schedule nightly database updates. So I use new Android WorkManager. My understanding is that once scheduled it will always run in the background independently from the app's lifecycle.
Is that right? My first tests show that Work is only being performed when the app is running.
val locationWork = PeriodicWorkRequest.Builder(UpdateDatabaseWorker::class.java, 24, TimeUnit.HOURS)
.addTag("DATABASE_UPDATE_SERVICE")
.build()
WorkManager.getInstance().enqueue(locationWork)
Based on various issues reported on the WorkManager bugtracker, their documentation is not completely precise about the exact behavior of the WorkManager in such edge cases.
On certain devices, apps are force stopped when the app is cleared from task manager, so that part is expected. ... source
Unfortunately, some devices implement killing the app from the recents menu as a force stop. Stock Android does not do this. When an app is force stopped, it cannot execute jobs, receive alarms or broadcasts, etc. So unfortunately, it's infeasible for us to address it - the problem lies in the OS and there is no workaround. source
The only issue that we have come across is the case where some Chinese OEMs treat swipe to dismiss from Recents as a force stop. When that happens, WorkManager will reschedule all pending jobs, next time the app starts up. Given that this is a CDD violation, there is not much more that WorkManager can do given its a client library. source
To add to this, if a device manufacturer has decided to modify stock Android to force-stop the app, WorkManager will stop working (as will JobScheduler, alarms, broadcast receivers, etc.). There is no way to work around this. Some device manufacturers do this, unfortunately, so in those cases WorkManager will stop working until the next time the app is launched. source
With intense testing of a OneTimeWorkRequest (without constraints) on a Pixel 2 XL with stock android the behavior is the following:
Task manager close:
Work continues (after a bit)
Reboot device (work running):
Work continues after reboot done
App info "Force stop":
Work stops, will only continue when app is started again
Reboot device (work was "Force Stopped"):
Work does not continue until the app is started again
You can find a complete list of different OEM behaviors on dontkillmyapp.com. It seems the Android team also acknowledges this issue and added a test for this into their CTS test for Android Q. source
My understanding is that once scheduled it will always run in the
background independently from the app's lifecycle. Is that right?
Yes. Based on the documentation
The task is still guaranteed to run, even if your app is force-quit or
the device is rebooted.
WorkManager chooses the appropriate way to run your task based on factors such 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.
WorkManager might use JobScheduler, Firebase JobDispatcher, or AlarmManager depending on the API level. It will repect the Doze and conaider all other constraints before executing the Work. You can expect some delay in Doze mode since it could wait for maintenance window.
Note:
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.
This is what documentation is saying:
Note: 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.
But there must be some condition. if that condition meet then WorkManager will run the task (this is important). Conditions like "only while device is charging and online"
Read this carefully, The WorkManager attempts to run your task at the interval you request, subject to the constraints you impose and its other requirements.
Here I found a good tutorial about how to use WorkManager for scheduling tasks : https://android.jlelse.eu/how-scheduling-work-with-new-android-jetpack-component-workmanager-852163f4825b

Categories

Resources