Jan 15 | 8:55 AM |
Mark M. | has entered the room |
Mark M. | turned on guest access |
Kris E. | has entered the room |
Kris E. |
Hello Mark, I was hoping you could help me with a JobScheduler issue I am having.
|
Mark M. |
I can try!
|
Jan 15 | 9:00 AM |
Kris E. |
So, after updating to Oreo I had to switch from AlarmManager to JobScheduler to do background updating of GPS, and the timing for JobScheduler firing is not very consistent. If the device is active it does fire around every 15 minutes but if the device is idle on modern versons of the OS (N+) it can be up to 3 hours between events.
|
Mark M. |
yes, that's the effect of Doze mode
|
Kris E. |
I was wonder if there was any best practices in setting up the job through the builder, or any settings that can be set to make it more like 15 minutes and not 3 hours which my client is not pleased with.
|
Mark M. |
um, well, not really
|
Mark M. |
users of the app can opt out of battery optimization for the app, which should help
|
Mark M. |
but otherwise the limits on background work are what they are
|
Kris E. |
So is the only way to force updates on a regular schedule using FCM?
|
Mark M. |
technically, on Android 9.0+, even that might not work, depending on where the app is in the "bucket" system
|
Mark M. |
but FCM at least can help
|
Kris E. |
Is there any way to check (or prompt the user) to opt out of battery optimization?
|
Mark M. |
if your app holds the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission, you can use ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS to ask the user to opt out of battery optimization
|
Mark M. |
however, at least in 2015, this might get you banned from the Play Store: https://commonsware.com/blog/2015/11/11/google-...
|
Kris E. |
And I guess that switching to WorkManager isn't going to make a difference then...
|
Mark M. |
no, because in the end, it uses JobScheduler, at least on versions of Android that have it
|
Jan 15 | 9:05 AM |
Mark M. |
in the end, right now, background work in Android is not very reliable, let alone frequent, from the end user's standpoint
|
Mark M. |
OTOH, battery life has dramatically improved
|
Kris E. |
Right, so really (this is for a customer who wants to keep track of where workers deliveries are) the only solution is compile against 7 and not have the app distributed in the App Store or force them to keep the app open. I am assuming that if the device is moving there will be more frequent updates, but if the device stays in one place and not active then it won't wake up.
|
Mark M. |
if the device is moving, full Doze mode does not kick in
|
Mark M. |
that is mostly for "the user is asleep and the device is sitting on the nightstand" scenario
|
Kris E. |
Yeah, and that is what my testing is showing, but in the field, even with the device moving it can be 30-45 minutes between updates. OK, thanks so much for your help, I just wanted to make sure that I was giving the most accurate information to client as possible. Thanks also for the books, they are invaluable -- my only regret is that I was developing on Android for 4 years before I found them.
|
Jan 15 | 9:10 AM |
Mark M. |
now that I check the release notes, it looks like jobs get deferred in partial Doze mode on Android 7.0+ -- see https://developer.android.com/about/versions/no...
|
Mark M. |
AlarmManager alarms seem like they will work in partial Doze mode, though
|
Mark M. |
and thanks for the kind words!
|
Kris E. |
In 7 alarmManager works, in 8 it crashes if the app isn't foreground.
|
Mark M. |
that may be a matter of what sort of PendingIntent you are using
|
Mark M. |
on Android 8.0+, use PendingIntent.getForegroundService(), and have the service call startForeground() right away
|
Kris E. |
Is that allowed? I thought would lead to Play store issues for sure.
|
Mark M. |
no, foreground services are Google's recommended approach
|
Mark M. |
*users* might not like them, as they clutter up the status bar
|
Mark M. |
in your case, my guess is that users don't really have much choice about whether to use the app
|
Jan 15 | 9:15 AM |
Kris E. |
So my old solution used a broadcastReceiver, how do I switch that to a pending intent?
|
Mark M. |
AlarmManager uses PendingIntent
|
Mark M. |
if you are using PendingIntent.getBroadcast() to create that PendingIntent, that is fine
|
Mark M. |
however, your receiver would need to either use JobIntentService (and then run risks with respect to JobManager) or a foreground service to get the work done
|
Mark M. |
and on Android 8.0+, to start a foreground service, call startForegroundService() instead of startService() (plus have the service call startForeground())
|
Kris E. |
OK, so in the onReceive I call PendingIntent.getForegroundService() and startForeground...
|
Mark M. |
if you are using AlarmManager, and you want that alarm to trigger a broadcast receiver, the PendingIntent you use with AlarmManager would be created using PendingIntent.getBroadcast(), pointing to that receiver
|
Mark M. |
alternatively, you can have AlarmManager directly invoke your service -- *then* you would use PendingIntent.getForegroundService() on Android 8.0+
|
Jan 15 | 9:20 AM |
Kris E. |
OK, I'll give that a shot. Thanks so much...
|
Mark M. |
you're welcome!
|
Kris E. | has left the room |
Kris E. | has entered the room |
Jan 15 | 9:40 AM |
Kris E. | has left the room |
Jan 15 | 10:00 AM |
Mark M. | turned off guest access |