I need to implement requestSync on button click and additionally periodic sync. I'm aware that requestSync isn't best practice, but that's just requirement, I have to do it.
Questions are:
1) if I set up periodic sync's pollFrequency to be 24hrs, and requestSync happened before 24hrs passed, will periodic sync will start counting from clean slate after requestSync or it will sync after 24hrs again?
2) What will happen if requestSync happened at the same time as periodic sync?
3) In the documentation it says pollFrequency has to be minimum 1hr, however I'm testing with 20 sec pollFrequency. Why is this possible?
4) syncing is happening not in 20 seconds but with varying intervals: 60secs, 5 secs, etc. Is this normal for intervals to be so different from each other?
5) Do I have to set some type of flag in the activity I'm setting periodic sync, that if it is first time the activity is being opened then set periodic sync, otherwise skip? Or system will know better than resetting same sync many times?
Related
Assume there is a scheduled work like this:
PeriodicWorkRequestBuilder<RefreshAuthWorker>(
repeatInterval = 15L,
repeatIntervalTimeUnit = TimeUnit.MINUTES,
flexTimeInterval = 5L,
flexTimeIntervalUnit = TimeUnit.MINUTES
)
Let's say, At 10th minute, I forcely killed/stopped the app.
Then reopen the app again after 10 mins.
by this time, the existing/killed work is overdue by 5 mins.
Now, What will the WorkManager do?
1.WorkManager respects the missed overdue work and do it immediately and then schedule the next work.
(or)
2.WorkManager ignores the past overdue work and schedules the next work?
This is a very important scenario to me because, let's say I have to refresh a token every 15 mins. But if WorkManager does like said in 1st point then, by the time I reopen the app, the token is already expired 5 mins ago and the next work is going to happen in 15 mins. So, it's a total of 20 mins with an expired token.
Can somebody who knows any idea what will the WorkManager do in such scenario, please help.
You can't do such things with a WorkManager.
Everything might happen if an application is forced stop. It is a problem of the user if he decides to do so. You should not care.
Are you sure you do not mean - clear from recent?
The priority of WM is saving resources like battery and network data. Timing is not a big concern. The idea is that you need some work to be executed for sure at some point. Like you want to upload a picture to a server.
What WorkManager does is - it creates a job in the JobScheduler. The job is executed when all the constraints are satisfied:
You have implicit constraints related to battery saving. You have some amount of resources that you can use based on your Power Bucket level. Also, the device's state is important. You can't predict when these constraints will be satisfied.
Also you have explicit constraints that you set. Like Connectivity, Battery level and in your case: "a period". But is a no period at all. When you have a "period" work on a higher level in the WorkManager - actually it means - many single jobs in the Job Scheduler. And each one of these jobs has the above implicit constraints and your explicit which is called - timing delay. So you see:
You start the work
WM schedules a job in JS with respective constraints
After 15min timing delay is satisfied
No one can tell what is the status of the implicit constraints. The device might be dozing, or you might have used all of your data usage for the last 24 hours or something like this.
5 At some point when all the constraints are satisfied - the Work starts and when it is finished:
6. You have a new job with the same constraints as before. So in theory your "15min period work" might be executed in 24 hours and after that, it might execute the second time in 15 minutes.
For my app I need to execute a task every hours but at specific time.
A server return to me a number of millisecond for example : 100ms, so I need to execute a task at :
00:00:00.100
01:00:00.100
02:00:00.100 etc ....
If the number is 3500 for example, I need to execute task at :
00:00:03.500
01:00:03.500
02:00:03.500 etc ...
I know how to run a task every 1 hour with an interval but I don't know how to do it at a specific time. If anyone has a solution :)
If you really need the exact ms (and I really, REALLY doubt that you do) you're out of luck. Android isn't a real time OS, because Linux isn't a real time OS, and doesn't make those assurances. If you just need really close to the time (like exact to the second), AlarmManager.setExactAndAllowWhileIdle will be called even in low power mode. However there is no repeating version of that, so you'll need to implement that yourself if needed. And AlarmManager doesn't persist alarms through reboot, so if you need it you'll have to do that. Finally you have about 10s to execute whatever you need or take appropriate measures like wake locks to do more.
This also requires the schedule exact alarm permission. Read the docs at https://developer.android.com/reference/android/app/AlarmManager#setExactAndAllowWhileIdle(int,%20long,%20android.app.PendingIntent)
Requirement - I need to get the user's location coordinates every 15 minutes roughly and post it to the server. It is necessary to post data roughly at these intervals.
Implementation - I've made a sync adapter instead of using AlarmManager as it saves battery. I've set ContentResolver.addPeriodicSync() to sync my app every 15 minutes roughly which gets the current location and posts to server.
Problem - In case there's no internet connection, I want to continue taking the user's location every 15 minutes and save them in the local sqlite database. When the internet comes back again next time then I'll post all the saved locations in one go so that server data remains consistent and after that sync will resume as normal.
The main problem is that when there's no internet then the sync stops and I stop getting periodic sync callbacks in my app and I'm not able to save data in the local database. So what I want is that even when there's no internet I keep getting callbacks at regular intervals till the internet comes back and auto sync starts again. Can the sync adapter do that?
One solution I can think of is that I get a broadcast when the Internet stops and at that moment I start using the AlarmManager to start a service every 15 minutes and get the location and save to local database. And when the internet comes back on then I stop using the AlarmManager and go back to auto syncing.
Solution 2 - Provided by David Medenjak below. It is also efficient due to AlarmManager's setInexactRepeating() behavior which tries to imitate Sync adapter's behavior by scheduling Alarms for different apps together to reduce the number of times the CPU wakes up. Also it leads to a little simpler implementation. Would this the better way than the previous solution comparing the pros and cons?
Still any better way to achieve this?
You are mixing two things:
Getting the user location every 15 minutes
Syncing the data with the server
If you start mixing those you have a service and sync adapter that are both strongly dependent on each other, you have to check for states which of those has run and which should run. You might end up with the exact thing that you want (syncing every 15 minutes, just cache it if user is offline) but it will be hard to test and maintain.
Always use a service that is run every 15 minutes to store the current user location.
Periodically sync all updates to the server. This may also happen to be every 15 minutes, but you should not depend on this.
By having one part just storing the location and the other part just synchronizing the data you will have a much easier time handling things. And you also don't have to worry about internet connection or the interval of the synchronizations (since sync adapters are not guaranteed to run at exact times).
Concerning battery life (comments)
There should be no big difference whether a SyncAdapter uses gps and posts it immediately or a service persists it for the time being until the adapter syncs it. As soon as a task has to run every x minutes the device will have to wake up.
There might be slight improvements if the synchronization is run at a slower rate compared to the service, since the gps alone might not need any internet connection.
IntentService - runs every 15 min (using AlarmManager) and saves the user location in the db and mark it as unsent.
SyncAdapter - runs every 15 min and ties to send all unsent locations to the server. On success mark the location as sent. Android will make sure it's only run when there is a internet connection.
Edit:
The key point is separating the two sub-tasks (also suggested by #David Medenjak):
1) Get a location update and store it in a db
2) Send the location updates to the server when there is a network connection.
The FusedLocationProvider has a method
requestLocationUpdates (GoogleApiClient client, LocationRequest request, PendingIntent callbackIntent)
for when your app is in the background. Link
This method is suited for the background use cases, more specifically
for receiving location updates, even when the app has been killed by
the system.
You can use a LocationRequest to set the priority, interval, power consumption. Link
When you receive the pending intent, you can insert the location in the database and request a sync using the sync adapter.
is there any way to reset the period of a PeriodicSync??
I mean, if the period is 10 mins, 7 mins have passed since the last sync, reset the period so next sync would by within 10 mins again, not 3.
ContentResolver has no methods for this. I've tried to:
Invoke ContentResolver.addPeriodicSync() over an existing PeriodicSync. As stated in the javadocs the period gets updated, but not resetted.
Stop and start the PeriodicSync. In this case the sync gets triggered when restarting, what I don't want to.
Thank you.
I have similar problem and not found way to update settings only:
ContentResolver.removePeriodicSync
and
ContentResolver.addPeriodicSync
change settings and as You write it runs sync
I am thinking about implementation of synchronization in my android application with ASyncTask and AlarmManager. Tried to do the same with SyncAdapter, but it just complicates the process and has other disadvantages (ContentProvider is needed, manual sync seems to be impossible if automated is disabled, user is needed etc.).
So, the question I have now with ASyncTask - let's say, it is started every 24 hours. But in case if there is not internet connection at this time, synchronization will not happen. Next time attempt will happen after 24 hours again. What can I do to avoid this? I.e. if 24 hours are already passed, then any time internet connection appeared, the task should be run. After this moment next 24 hours to be counted.
For ex.,
sync 1 - day 1 12:00 (successful)
sync 2 - day 2 12:00 (failed - no internet connection)
sync 3 - day 2 20:00 (successful, internet connection appeared)
sync 4 - day 3 20:00 (successful)
Believe, I can either run my task more often (for ex., each 30 minutes) and store time of last update somewhere. Or, I can listen for event when internet connection appears. What is the best approach? Or, is there some standard functionality for the same?
I would go with the BroadcastListener registered to do the syncing when internet connection is available. You could use the SharedPreferences to indicate for this listener, that sync is needed - because I guess you'd have to register this listener in the manifest, I think there's no way to handle this dynamically.
This way you can be sure that sync will happen if there's net connection available, while the 30-min-polling might miss the chance.