Doing a job in background is very critical, specially with Doze mode and App stand by. In this presentation I have explained how can you schedule a job intelligently and conserve user's battery and network data.
Presentation on Android application life cycle and saved instancestate
Job schedulers android
1. Job Schedulers in Android
By Deesha Vora (@Deesharv)
Co-founder & Chief of Product @SuperWiseSite
Email: deesha@superwise.site
2. What’s JobScheduler ?
Job Service
The work you are
wanting to do.
Extends Job Service
class. Job runs on main
thread.
Need to implement
● onStartJob()
● jobFinished()
Job Info
Job Info object is
conditions under which
Job service will execute.
Need to Give
● JobID
● JobService
● Criteria(s) for
trigger.
[Network, Charging/Idle,
Content URI (API 24),
Backoff-Policy, Periodic]
Job Scheduler
Job Scheduler is used to
schedule the job.
schedule() call using
JobInfo object and Job
with similar ID will be
replaced.
3.
4. JOB SERVICE
public class MyJobService extends JobService {
boolean isWorking = false;
boolean jobCancelled = false;
// Called by the Android system when it's time to run the job
@Override
public boolean onStartJob(JobParameters jobParameters) {
Log.d(“TAG”, "Job started!");
isWorking = true;
startWorkOnNewThread(jobParameters);
5. JOB SERVICE
// Services do NOT run on a separate thread
return isWorking;
}
private void startWorkOnNewThread(final JobParameters jobParameters) {
new Thread(new Runnable() {
public void run() {
doWork(jobParameters);
}
}).start(); }
6. JOB SERVICE
private void doWork(JobParameters jobParameters) {
// 10 seconds of working (1000*10ms)
for (int i = 0; i < 1000; i++) {
// If the job has been cancelled, stop working; the job will be rescheduled.
if (jobCancelled)
return;
try { Thread.sleep(10); } catch (Exception e) { }
}
Log.d(TAG, "Job finished!");
isWorking = false;
boolean needsReschedule = false;
jobFinished(jobParameters, needsReschedule);
}
7. JOB SERVICE
// Called if the job was cancelled before being finished
@Override
public boolean onStopJob(JobParameters jobParameters) {
Log.d(TAG, "Job cancelled before being completed.");
jobCancelled = true;
boolean needsReschedule = isWorking;
jobFinished(jobParameters, needsReschedule);
return needsReschedule;
} }
8. JOB SERVICE to MANIFEST
<service
android:name=".MyJobService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
9. SET UP JOB INFO
ComponentName componentName = new ComponentName(this,
MyJobService.class);
JobInfo jobInfo = new JobInfo.Builder(12, componentName)
.setRequiresCharging(true)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.build();
10. Time to Schedule
JobScheduler jobScheduler =
(JobScheduler)getSystemService(JOB_SCHEDULER_SERVICE);
int resultCode = jobScheduler.schedule(jobInfo);
if (resultCode == JobScheduler.RESULT_SUCCESS) {
Log.d(TAG, "Job scheduled!");
} else {
Log.d(TAG, "Job not scheduled");
}
11. Intelligent Jon-
Schedulers
Scheduling this work intelligently can
improve your app’s performance
Note: Use Handler if app is in
foreground
AlarmManager
GCM Network Manager
Firebase JobDispatcher
SyncAdapter
Services
12. Alarm Manger
● We should only use AlarmManager API for tasks that must execute at a
specific time or after specific time.
● This does not provide more robust execution conditions like device is idle,
network is available or charging detect.
13. GCM Network Manager
● Has all the schedule features from JobScheduler.
● Can also use below Android 5.0 (API level 21). From API level 23 or higher, GCM
Network Manager uses the framework’s JobScheduler.
● Uses the scheduling engine inside Google Play services
● Google has strongly recommended for GCM users to upgrade to FCM and
instead use Firebase Job Dispatcher for scheduling any tasks.
14. Firebase Job Dispatcher
● supports backward compatibility (below API 21) & works on all recent versions
of Android (API 9+).
● If device do not have Google play services installed , this library internally uses
AlarmManager. If Google Play service is available on the device then it uses the
scheduling engine inside Google Play services.
● It uses AlarmManager to support API levels <= 21 if Google Play services is
unavailable. For the device running on API level 21, it uses JobScheduler
15. Sync Adapter
● Sync adapters are designed specifically for syncing data between a device and
the cloud.
● The Android system will try to batch outgoing syncs to save battery life and
transfers that are unable to run will queue up for transfer at some later time
● Android N (API level 24), the SyncManager sits on top of the JobScheduler. You
should only use the SyncAdapter class if you require the additional functionality
that it provides.
16. DOZE & APP Stand by restrictions
● The system ignores wake locks.
● The system does not allow sync adapters to run.
● The system does not allow JobScheduler to run
● Standard AlarmManager alarms (including setExact() and setWindow()) are
deferred to the next maintenance window.
○ The system does not perform Wi-Fi scans.
● Network access is suspended.
17. DOZE & APP Standby solutions
Alarm Manger
● API 23 introduces two new AlarmManager methods: setAndAllowWhileIdle()
and setExactAndAllowWhileIdle().
If the device is idle for long periods of time, the system allows idle apps network
access around once a day
● Whitelist request for the app, to allow partial wake lock
● Acceptable whitelist cases
18. Data cost sensitivity Job-Schedulers in Android P
● With Android P, JobScheduler has been improved to let it better handle
network-related jobs for the user, in coordination with network status signals
provided separately by carriers.
● Jobs can now declare their estimated data size, signal prefetching, and specify
detailed network requirements—carriers can report networks as being
congested or unmetered.
19. Data cost sensitivity …
● When adding jobs, make sure to use setEstimatedNetworkBytes(),
setIsPrefetch(), and setRequiredNetwork()
● When your job executes, be sure to use the Network object returned by
JobParameters.getNetwork()
20. Thank you !
By Deesha Vora (@Deesharv)
Co-founder & Chief of Product @SuperWiseSite
Email: deesha@superwise.site
Job-Scheduler libraries
https://github.com/evernote/android-job
https://github.com/yigit/android-priority-jobqueue
Editor's Notes
Advantage of JoScheduler -
1. Dont worry for the result, JobScheduler will Retry and Reshedule your Job
2. Jobs will be batched if the creitira is similar like Network
3. App will be Doze aware
4. Minimum latency and override deadline
5. Periodic
6. Persistent
7. Extras
8. You can schedule a job using JobScheduler, which you will retrieve from the system. Then, call schedule() using your JobInfo object, and you are good to go. No worries needed.
public class MyJobService extends JobService {
private static final String TAG = MyJobService.class.getSimpleName();
boolean isWorking = false;
boolean jobCancelled = false;
// Called by the Android system when it's time to run the job
@Override
public boolean onStartJob(JobParameters jobParameters) {
Log.d(TAG, "Job started!");
isWorking = true;
// We need 'jobParameters' so we can call 'jobFinished'
startWorkOnNewThread(jobParameters); // Services do NOT run on a separate thread
return isWorking;
}
private void startWorkOnNewThread(final JobParameters jobParameters) {
new Thread(new Runnable() {
public void run() {
doWork(jobParameters);
}
}).start();
}
private void doWork(JobParameters jobParameters) {
// 10 seconds of working (1000*10ms)
for (int i = 0; i < 1000; i++) {
// If the job has been cancelled, stop working; the job will be rescheduled.
if (jobCancelled)
return;
try { Thread.sleep(10); } catch (Exception e) { }
}
Log.d(TAG, "Job finished!");
isWorking = false;
boolean needsReschedule = false;
jobFinished(jobParameters, needsReschedule);
}
// Called if the job was cancelled before being finished
@Override
public boolean onStopJob(JobParameters jobParameters) {
Log.d(TAG, "Job cancelled before being completed.");
jobCancelled = true;
boolean needsReschedule = isWorking;
jobFinished(jobParameters, needsReschedule);
return needsReschedule;
}
}
We should only use AlarmManager API for tasks that must execute at a specific time. This does not provide more robust execution conditions like device is idle, network is available or charging detect.
to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.
The framework continues to provide the SyncAdapter class for managing tasks that sync data between the device and a server. Sync adapters are designed specifically for syncing data between a device and the cloud; you should only use them for this type of task. Sync adapters are more complex to implement than the libraries and APIs mentioned above, because they require at least a fake authenticator and content provider implementation. For these reasons, you typically should not create a sync adapter just to sync data to the cloud in the background. Wherever possible, you should instead use JobScheduler, Firebase JobDispatcher, or GCM Network Manager .
In Android N (API level 24), the SyncManager sits on top of the JobScheduler. You should only use the SyncAdapter class if you require the additional functionality that it provides.
SERVICES:
The Services framework allows you to perform long-running operations in the background. We recommend foreground services for tasks, such as playing music, which need to stay resident for the user. Bound services also continue to be useful for various use cases: for example, when a service needs to run only when a user is viewing a fragment or activity.
You should avoid using started services that run perpetually or perform periodic work, since they continue to use device resources even when they are not performing useful tasks. Instead, you should use other solutions that this page describes, and that provide native lifecycle management. Use started services only as a last resort. The Android platform may not support started services in the future.
Captive Internet Portals, VPNs, and proxies can pose Internet-connectivity detection problems. A library or API may think the Internet is available, but your service may not be accessible. Fail gracefully and reschedule as few of your tasks as possible.
Depending on the conditions you assign for running a task, such as network availability, after the task is triggered, a change may occur so that those conditions are no longer met. In such a case, your operation may fail unexpectedly and repeatedly. For this reason, you should code your background task logic to notice when tasks are failing persistently, and perform exponential back-off to avoid inadvertently over-using resources.
Remember to use exponential backoff when rescheduling any work, especially when using AlarmManager. If your app uses JobScheduler, Firebase JobDispatcher, or sync adapters, exponential backoff is automatically used.
https://android.jlelse.eu/schedule-tasks-and-jobs-intelligently-in-android-e0b0d9201777
Use
Doze is particularly likely to affect activities that AlarmManager alarms and timers manage, because alarms in Android 5.1 (API level 22) or lower do not fire when the system is in Doze.
To help with scheduling alarms, Android 6.0 (API level 23) introduces two new AlarmManagermethods: setAndAllowWhileIdle() and setExactAndAllowWhileIdle(). With these methods, you can set alarms that will fire even if the device is in Doze.
Note: Neither setAndAllowWhileIdle() nor setExactAndAllowWhileIdle() can fire alarms more than once per 9 minutes, per app.
App Standby allows the system to determine that an app is idle when the user is not actively using it. The system makes this determination when the user does not touch the app for a certain period of time and none of the following conditions applies:
The user explicitly launches the app.
The app has a process currently in the foreground (either as an activity or foreground service, or in use by another activity or foreground service).
Note: You should only use a foreground service for tasks the user expects the system to execute immediately or without interruption. Such cases include uploading a photo to social media, or playing music even while the music-player app is not in the foreground. You should not start a foreground service simply to prevent the system from determining that your app is idle.
The app generates a notification that users see on the lock screen or in the notification tray.
The app is an active device admin app (for example, a device policy controller). Although they generally run in the background, device admin apps never enter App Standby because they must remain available to receive policy from a server at any time.
When the user plugs the device into a power supply, the system releases apps from the standby state, allowing them to freely access the network and to execute any pending jobs and syncs. If the device is idle for long periods of time, the system allows idle apps network access around once a day.
GCM Network Manager is also meant for performing repeated or one-off, non-imminent work while keeping battery life in mind.
so this class will only work if the Google Play services is installed on the device.
The Firebase JobDispatcher is also a library for scheduling background jobs. It is also used to support backward compatibility (below API level 21) and works on all recent versions of Android (API level 9+).
This library will also works when running device do not have Google play services installed and wants to schedule a job in the application. In this condition this library internally uses AlarmManager. If Google Play service is available on the device then it uses the scheduling engine inside Google Play services.
Tip: It uses AlarmManager to support API levels <= 21 if Google Play services is unavailable.
For the device running on API level 21, it uses JobScheduler. This library also has the same framework so there is no change in functionality.
Sync adapters are designed specifically for syncing data between a device and the cloud. It should be only use for this type of task. Syncs could be triggered from data changes in either the cloud or device, or by elapsed time and time of day. The Android system will try to batch outgoing syncs to save battery life and transfers that are unable to run will queue up for transfer at some later time. The system will attempt syncs only when the device is connected to a network.
Wherever possible, it is advised via Google to use JobScheduler, Firebase JobDispatcher, or GCM Network Manager.
In Android N (API level 24), the SyncManager sits on top of the JobScheduler. You should only use the SyncAdapter class if you require the additional functionality that it provides.
The sync adapter component in your app encapsulates the code for the tasks that transfer data between the device and a server. Based on the scheduling and triggers you provide in your app, the sync adapter framework runs the code in the sync adapter component. To add a sync adapter component to your app, you need to add the following pieces:
Sync adapter class.
A class that wraps your data transfer code in an interface compatible with the sync adapter framework.
Bound Service.
A component that allows the sync adapter framework to run the code in your sync adapter class.
Sync adapter XML metadata file.
A file containing information about your sync adapter. The framework reads this file to find out how to load and schedule your data transfer.
Declarations in the app manifest.
XML that declares the bound service and points to sync adapter-specific metadata.
This lesson shows you how to define these elements.
https://android.jlelse.eu/schedule-tasks-and-jobs-intelligently-in-android-e0b0d9201777
If you need to set alarms that fire while in Doze, use setAndAllowWhileIdle() or setExactAndAllowWhileIdle().
Alarms set with setAlarmClock() continue to fire normally — the system exits Doze shortly before those alarms fire.
Doze is particularly likely to affect activities that AlarmManager alarms and timers manage, because alarms in Android 5.1 (API level 22) or lower do not fire when the system is in Doze.
To help with scheduling alarms, Android 6.0 (API level 23) introduces two new AlarmManagermethods: setAndAllowWhileIdle() and setExactAndAllowWhileIdle(). With these methods, you can set alarms that will fire even if the device is in Doze.
Note: Neither setAndAllowWhileIdle() nor setExactAndAllowWhileIdle() can fire alarms more than once per 9 minutes, per app.
App Standby allows the system to determine that an app is idle when the user is not actively using it. The system makes this determination when the user does not touch the app for a certain period of time and none of the following conditions applies:
The user explicitly launches the app.
The app has a process currently in the foreground (either as an activity or foreground service, or in use by another activity or foreground service).
Note: You should only use a foreground service for tasks the user expects the system to execute immediately or without interruption. Such cases include uploading a photo to social media, or playing music even while the music-player app is not in the foreground. You should not start a foreground service simply to prevent the system from determining that your app is idle.
The app generates a notification that users see on the lock screen or in the notification tray.
The app is an active device admin app (for example, a device policy controller). Although they generally run in the background, device admin apps never enter App Standby because they must remain available to receive policy from a server at any time.
When the user plugs the device into a power supply, the system releases apps from the standby state, allowing them to freely access the network and to execute any pending jobs and syncs. If the device is idle for long periods of time, the system allows idle apps network access around once a day.
https://android.jlelse.eu/schedule-tasks-and-jobs-intelligently-in-android-e0b0d9201777
Doze is particularly likely to affect activities that AlarmManager alarms and timers manage, because alarms in Android 5.1 (API level 22) or lower do not fire when the system is in Doze.
To help with scheduling alarms, Android 6.0 (API level 23) introduces two new AlarmManagermethods: setAndAllowWhileIdle() and setExactAndAllowWhileIdle(). With these methods, you can set alarms that will fire even if the device is in Doze.
Note: Neither setAndAllowWhileIdle() nor setExactAndAllowWhileIdle() can fire alarms more than once per 9 minutes, per app.
App Standby allows the system to determine that an app is idle when the user is not actively using it. The system makes this determination when the user does not touch the app for a certain period of time and none of the following conditions applies:
The user explicitly launches the app.
The app has a process currently in the foreground (either as an activity or foreground service, or in use by another activity or foreground service).
Note: You should only use a foreground service for tasks the user expects the system to execute immediately or without interruption. Such cases include uploading a photo to social media, or playing music even while the music-player app is not in the foreground. You should not start a foreground service simply to prevent the system from determining that your app is idle.
The app generates a notification that users see on the lock screen or in the notification tray.
The app is an active device admin app (for example, a device policy controller). Although they generally run in the background, device admin apps never enter App Standby because they must remain available to receive policy from a server at any time.
When the user plugs the device into a power supply, the system releases apps from the standby state, allowing them to freely access the network and to execute any pending jobs and syncs. If the device is idle for long periods of time, the system allows idle apps network access around once a day.
Users can manually configure the whitelist in Settings > Battery > Battery Optimization. Alternatively, the system provides ways for apps to ask users to whitelist them.
An app can fire the ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS intent to take the user directly to the Battery Optimization, where they can add the app.
An app holding the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission can trigger a system dialog to let the user add the app to the whitelist directly, without going to settings. The app fires a ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS Intent to trigger the dialog.
The user can manually remove apps from the whitelist as needed.