So I know WorkManager utilizes JobScheduler on supported APIs but there doesnt seem to be any way to make WorkManager work persistent across reboots? Is the only option to request the BOOT_COMPLETED permission and reschedule jobs?
To answer your question: You don't need to do anything if the device is rebooted. WorkManager keeps scheduling your Work without any additional requirement from your side.
WorkManager persists Work requests in its internal Room database. This allows it to guarantee Work execution across device restart.
The documentation covers this as this blog "Introducing WorkManager" that the team wrote last year.
WorkManager is actually used to persist deferrable tasks even after your app exits and the device restarts, please refer to the docs. It uses JobScheduler for api 23 and above and broadcastReceiver and AlarmManger on api 14 to 22. You can use constraints to check battery status, network coverage ...etc depending your particular usecase. You just have to be careful not to remove or rename your existing classes after they are added in the queue because WorkManager uses it's internal database to store those classes and your app will crash if you remove them or rename them.
Related
I have some critical data to be synced with the server every half an hour or so. I tried using WorkManager but turns out that it cannot run reliably even if I have REQUEST_IGNORE_BATTERY_OPTIMIZATIONS. So then I thought I should use AlarmManager, but they wrote in the docs:
This is a case where you might be tempted to use a repeating alarm. But if you own the server that is hosting your app's data, using Google Cloud Messaging (GCM) in conjunction with sync adapter is a better solution than AlarmManager.
So then I went to SyncAdapter docs and they mentioned with a star:
We recommended WorkManager as the recommended solution for most background processing use cases. Please reference the background processing guide to learn which solution works best for you.
I also read in quite a few blog posts that Sync Manager will be phased out or replaced in the near future.
So I am back again with WorkManager. Is it a good idea to use SyncAdapter in 2020?
If you need to have a sync reliably every 30 minutes, use Firebase Cloud Messaging (the evolution of GCM) and use WorkManager to enqueue a Worker that does the actual backup upload when the application on the device receives the message.
If your application is going to be always in the background you can expect that it will drift into having less and less execution time while in the background. Ignoring battery optimization helps in that case.
Here you have the information regarding the different power buckets.
Note This is for stock Android, some OEMs add additional battery optimization that further reduce background tasks. You can see a collection on issues on https://dontkillmyapp.com/
I am making an android app, that mostly runs in the background, communicating with firebase real-time database. My apps need to be in sync with firebase database all the time. Currently, I am only doing database write operations in my service. I have been using FCM for syncing database states, but FCM is not very reliable in my case.
Will it be wise decision to listen for database changes by attaching a listener to firebase database? By attaching a listener, I think it will keep an open connection with the database, which might increase battery usage.
My concern here is related to battery usage.
I think you should opt for Intelligent Job-Scheduling for Android
Scheduling this work intelligently can improve your app’s performance, along with aspects of system health such as battery life. JobScheduler does this scheduling work for you.
In addition to JobScheduler, there are several other facilities available to help your app schedule work. These include:
AlarmManager
Firebase JobDispatcher
SyncAdapter
Additional Facilities
SyncAdapter can help you keep syncing between data
Also please consider
Firebase JobDispatcher can be used when on several time period you want to check for database update or feature like backup data on scheduled time.
Please read more at this link on Official Site
Android provides different APIs for scheduling task.
JobScheduler
AlarmManager
Firebase JobDispatcher
Check this about Job Scheduling.
All of them have their benefits and downsides. JobScheduler became available from Android 5.0 (API level 21). Firebase JobDispatcher needs Google Play preinstalled.
You can use Android-Job library. This library schedule jobs depending on your requirements. This library decides which API suits your job. For more details check Android-Job library. Its easy to use.
If you are using in your code listeners that are not removed according to the life-cycle of the activity, you need to know that your app will keep an open connection with the database and will increase the battery usage for sure.
Because also of the newtowrk traffic, Android will stop your process from networking, when it's not longer visible in the foreground. This is to prevent poorly behaved apps from consuming too many resources. When a process like this can be killed, depends on the Android version and device manufacturer. Given their efforts to reduce background data usage (to improve battery life) and I'd recommend not relying on this.
If your apps needs to continue networking when the user is no longer using it, you'll have to start a foreground service, which also requires that you show a notification that indicates to the user that your app is still running.
The new limitations on running background services is explained here and here.
This new behaviour is apparently to stop apps doing lots of stuff in the background without the user even being aware, which is fair enough.
However, one of the suggested workarounds is to use a scheduled job instead. But doesn't that also potentially result in the app "doing lots of stuff in the background without the user even being aware"? The only difference being that Android decides exactly when this stuff is done, rather than the app.
So, what exactly is the point of the new limitations? Or maybe I've missed something fundamental.
EDIT: This is not a duplicate of this question... that one is about using startServiceInForeground() as an alternative (or about documentation relating to that) whereas this question is about using a scheduled job as an alternative (and whether that defeat the purpose of the new limitations completely). These are completely different alternatives.
I see your point.
Seems to me (after reading through the docs) this is the only pro that we get using the new JobScheduler.
However if you look through Job Scheduler Improvements in O
Scheduled jobs now support several new constraints:
JobInfo.isRequireStorageNotLow()
Job does not run if the device's available storage is low.
JobInfo.isRequireBatteryNotLow()
Job does not run if the battery level is at or below the criticial threshold; this is the level at which the device shows the Low battery warning system dialog.
NETWORK_TYPE_METERED
Job requires a metered network connection, like most cellular data plans.
You would notice that for each JobInfo you get to specify which constraints need to hold for the job to start.
Once the job has been started, it is then free to use as many resources as it wants for however long it wants.
That seems to be true, since there is no indication from the docs on what would happen if/when the resources are required again. However you can break down your big task into smaller tasks and then use the [JobScheduler.enque()](https://developer.android.com/reference/android/app/job/JobScheduler.html#enqueue(android.app.job.JobInfo, android.app.job.JobWorkItem)) method to ensure that the JobScheduler stops before starting next job in queue if the System otherwise requires resources. However this may not be necessary if JobScheduler provides a method or a callback to the Job to pause/stop (doubtful since the docs don't get into it) I've never tried it myself.
Conclusion :
So in conclusion while the new API does not completely restrict the Background Services to run while required resources are available, it does however provide a platform for the coder to restrict them to start only when above mentioned conditions are met while also restricting min lines of code required. Which should in most cases minimize battery usage and provide a smoother experience to user.
I want to be able to recover from crash/closing the app or just device being disconnected.
Currently when I detect that the network is out for my Android device I save the Call created with RetroFit2 in a stack (to process later). If the user were to close the app or restart the device I lose the possibility to save these calls anywhere...
My question is the following, how can I save a RetroFit Call or an OkHttp3 Request?
None of them is serializable or nor can I convert them to strings from what I could see looking at the code.
Use android priority jobqueue by Yigit Boyar (one of the google android guys). It'll serailize your jobs, detect network changes (and respond accordingly) and persist even through device reboots (let alone app crashes). Plus a ton of other features. Just take a look. It is not exactly what you requested but it's a better solution. It's Magic.
Starting with v2, Job Queue can be integrated with JobScheduler or GCMNetworkManager. This integration allows Job Queue to wake up the aplication based on the criterias of the Jobs it has. You can see the deatails on the related wiki page. The Scheduler API is flexible such that you can implement a custom version of it if your target market does not have Google Play Services.
Try it and you'll be glad you did, as I've been. It filled the huge gap in my code that I spent weeks hacking together with spit, ducktape and faith.
Background
I wanted to use the new JobScheduler API that was presented on Lollipop, but sadly it doesn't have an official port for pre-Lollipop.
However, there is the GcmTaskService, which provides very similar functionalities.
The problem
This API is quite new, so there are very few places to look for information of how to use it (here and here, for example).
The questions
I have a few questions about this new API :
It seems that it requires Google Play Services (here) to be used (except for when using Lollipop version of Android, which will use the normal JobScheduler). What should I do in case the Google play services aren't available?
It seems that even though I've used "setPersisted(true)" for a repeated task, when I restart the device the task won't be called again. How come?
EDIT: that's because I missed a permission of RECEIVE_BOOT_COMPLETED .
What is the default behavior of a task, in case I don't use "setRequiredNetwork" ? Is it "NETWORK_STATE_ANY" ?
The docs say about what's returned from onRunTask , I can return any of the values "RESULT_FAILURE", "RESULT_RESCHEDULE", "RESULT_SUCCESS" (info here). It seems both the FAILURE and SUCCESS options will do the same thing - remove the task from the queue. Is it true? If so, what exactly is the difference between them ? Do they function differently?
Are "TaskParams" used only for the tag of the task? Can I somehow pass a bundle to the task using the API? Otherwise, I would need to set a DB for storing what should be passed to the tasks, right?
Is it possible for the app to get the queue of the tasks? I know it's possible using adb, but is it possible using the API too?
They say (here) that each task has a wakelock of up to 3 minutes. What should be done if the task needs more than that? Should it acquire another wakelock for itself? Will the API warn that the wakelock was released? Here's what the docs say:
The scheduler will hold a PowerManager.WakeLock for your service,
however after three minutes of execution if your task has not returned
it will be considered to have timed out, and the wakelock will be
released. Rescheduling your task at this point will have no effect. If
you suspect your task will run longer than this you should start your
own service explicitly or use some other mechanism; this API is
intended for relatively quick network operations.
They say (here) that all networks-tasks are removed each time the app gets upgraded/replaced, and there is a call for "onInitializeTasks" when this happens, and that you can re-schedule them again. How can I re-schedule the tasks? I don't think I can even get the list of tasks...
Is it possible to tell the task to prefer specific times during the day ? For example, between the 14:00-15:00 ?
I've noticed that if you schedule a task, and then you force-stop and/or clear data of the app, the task will still run. How can I avoid this behavior?
jacktech24 did a really good job, but i will try as well in case there are any lingering questions.
It seems that it requires Google Play Services (here) to be used (except for when using Lollipop version of Android, which will use the normal JobScheduler). What should I do in case the Google play services aren't available?*
You can't use this API if Google Play Services isn't available. Rather, the Google Play Services client library is designed to request that the user download and install Google Play Services if it detects that it's missing, but I don't believe that the GcmNetworkManager does this.
What is the default behavior of a task, in case I don't use "setRequiredNetwork" ? Is it "NETWORK_STATE_ANY" ?*
The javadoc describes which is the default.
The docs say about what's returned from onRunTask , I can return any of the values "RESULT_FAILURE", "RESULT_RESCHEDULE", "RESULT_SUCCESS" (info here). It seems both the FAILURE and SUCCESS options will do the same thing - remove the task from the queue. Is it true? If so, what exactly is the difference between them ? Do they function differently?*
The only difference between these 2 is that in the adb shell dumpsys it will display what you returned, so you can use this to troubleshoot issues.
The other reason is that if the task fails, it is strange to require the client return a "success."
Are "TaskParams" used only for the tag of the task? Can I somehow pass a bundle to the task using the API? Otherwise, I would need to set a DB for storing what should be passed to the tasks, right?*
In the next version of GmsCore the ability to add a bundle to the task should be supported.
Is it possible for the app to get the queue of the tasks? I know it's possible using adb, but is it possible using the API too?
No it's not possible. Instead you should perform the cancel when you want it and if the task is not there it will be a no-op. Similarly you should schedule the task at the point in your code where you would have queried for the list of tasks. use setUpdateCurrent=false to ensure that it doesn't update the pre-existing task. The AlarmManager works in a similar way in that you would set the alarm regardless of whether the alarm was already set - the api was designed to follow this.
They say (here) that each task has a wakelock of up to 3 minutes. What should be done if the task needs more than that? Should it acquire another wakelock for itself? Will the API warn that the wakelock was released? Here's what the docs say:*
Yes, the app should acquire its own wakelock and everything will be fine. The reason the scheduler releases the wakelock after 3 mins is because in practice having an unlimited wakelock timeout only leads to really hard to track down battery drain bugs. If you need longer than 3 mins you have a sophisticated enough use-case that you can dig into how the PowerManager APIs work and call the acquire()/release() yourself (it's really quite simple, the fact that the network manager does it for you is more of a politeness than anything else).
They say (here) that all networks-tasks are removed each time the app gets upgraded/replaced, and there is a call for "onInitializeTasks" when this happens, and that you can re-schedule them again. How can I re-schedule the tasks? I don't think I can even get the list of tasks...*
You reschedule the tasks the same way you scheduled them in the first place. Whatever function you used to schedule them, call that function from GcmTaskService#onInitializeTasks. This was done to avoid lingering tasks across app logic changes. Consider the situation where a developer changes their task timetable, and starts using a different tag. They would be required to call cancel(old_tag) after they'd detected the upgrade (which they'd have to add more code to do), which would mean they'd need a reference to the old (unused) tag even in their new code. This would imply that a tag is a stable identifier that shouldn't change across app upgrades - which shouldn't be a requirement for this api.
Is it possible to tell the task to prefer specific times during the day ? For example, between the 14:00-15:00 ?*
No, this type of background scheduling causes all sorts of problems with herding across large populations of devices. I.e. if 1 device runs a job at 15:00 that is probably fine. But if 1x10e6 do suddenly your server is in serious problems.
I've noticed that if you schedule a task, and then you force-stop and/or clear data of the app, the task will still run. How can I avoid this behavior?*
Unfortunately you can't, but this is not intentional and should be changed - there should be no way for an app to run after the user has explicitly stopped it.
you can find answers to most of your questions it here.
https://github.com/jacktech24/gcmnetworkmanager-android-example/blob/master/README.md
To answers that are not answered there
7: You won't get notified when wakelock is removed, and as they say in documentation, this API is only for short tasks, if you have longer, write your own implementation
9: No you can't as of now, the API doesn't allow it
10: That's because Google Play services are taking care of it, and there is no way around it. You have to detect in the service whether the app is setup (I expect that's your problem) eg. configuration is created etc. and eventually cancel all tasks when one of them is called.