OLD | NEW |
(Empty) | |
| 1 # Quick Start Guide to using BackgroundTaskScheduler |
| 2 |
| 3 ## Background |
| 4 |
| 5 In Android M+ it is encouraged to use `JobScheduler` for all background jobs, |
| 6 instead of using things like `IntentService` or polling using alarms. Using the |
| 7 system API is beneficial as it has a full view of what goes on in the system and |
| 8 can schedule jobs accordingly. |
| 9 |
| 10 However, this functionality was introduced in Android L, and |
| 11 the API has been very stable since Android M. This means that we also need a |
| 12 similar framework for older versions of Android, which is provided by |
| 13 Google Play services. We prefer system APIs, since they do not require including |
| 14 external libraries which bloats the APK size of Chrome and adds unnecessary |
| 15 complexity. The GcmNetworkManager is only used when the system API is not |
| 16 available. |
| 17 |
| 18 The `background_task_scheduler` component provides a new framework for use |
| 19 within chromium to schedule and execute background jobs using the frameworks |
| 20 available on a given version of Android. |
| 21 The public API of the framework is similar to that of the Android |
| 22 `JobScheduler`, but it is backed by either the system `JobScheduler` API or by |
| 23 GcmNetworkManager. What service is used to back the framework remains unknown to |
| 24 callers of the API. |
| 25 |
| 26 ## What is a task |
| 27 |
| 28 A task is defined as a class that implements the `BackgroundTask` interface, |
| 29 which looks like this: |
| 30 |
| 31 ```java |
| 32 interface BackgroundTask { |
| 33 interface TaskFinishedCallback { |
| 34 void taskFinished(boolean needsReschedule); |
| 35 } |
| 36 |
| 37 boolean onStartTask(Context context, |
| 38 TaskParameters taskParameters, |
| 39 TaskFinishedCallback callback); |
| 40 boolean onStopTask(Context context, |
| 41 TaskParameters taskParameters); |
| 42 } |
| 43 ``` |
| 44 |
| 45 **Any class implementing this interface must have a public constructor which tak
es |
| 46 no arguments.** |
| 47 |
| 48 A task must also have a unique ID, and it must be listed in `TaskIds` to ensure |
| 49 there is no overlap between different tasks. |
| 50 |
| 51 ## How to schedule a task |
| 52 |
| 53 A task is scheduled by creating an object containing information about the task, |
| 54 such as when to run it, whether it requires battery, and other similar |
| 55 constraints. This object is called `TaskInfo` and has a builder you can use |
| 56 to set all the relevant fields. |
| 57 |
| 58 There are two main types of tasks; one-off tasks and periodic tasks. One-off |
| 59 tasks are only executed once, whereas periodic tasks are executed once per |
| 60 a defined interval. |
| 61 |
| 62 As an example for how to create a one-off task that executes in 200 minutes, |
| 63 you can do the following: |
| 64 |
| 65 ```java |
| 66 TaskInfo.createOneOffTask(TaskIds.YOUR_FEATURE, |
| 67 MyBackgroundTask.class, |
| 68 TimeUnit.MINUTES.toMillis(200)).build(); |
| 69 ``` |
| 70 |
| 71 For a periodic task that executes every 200 minutes, you can call: |
| 72 |
| 73 ```java |
| 74 TaskInfo.createPeriodicTask(TaskIds.YOUR_FEATURE, |
| 75 MyBackgroundTask.class, |
| 76 TimeUnit.MINUTES.toMillis(200)).build(); |
| 77 ``` |
| 78 |
| 79 Typically you will also set other required parameters such as what type of |
| 80 network conditions are necessary and whether the task requires the device to |
| 81 be charging. They can be set on the builder like this: |
| 82 |
| 83 ```java |
| 84 TaskInfo.createOneOffTask(TaskIds.YOUR_FEATURE, |
| 85 MyBackgroundTask.class, |
| 86 TimeUnit.MINUTES.toMillis(100) |
| 87 TimeUnit.MINUTES.toMillis(200)) |
| 88 .setRequiresCharging(true) |
| 89 .setRequiredNetworkType(TaskInfo.NETWORK_TYPE_UNMETERE
D) |
| 90 .build(); |
| 91 ``` |
| 92 |
| 93 When the task is ready for scheduling, you use the |
| 94 `BackgroundTaskSchedulerFactory` to get the current instance of the |
| 95 `BackgroundTaskScheduler` and use it to schedule the job. |
| 96 |
| 97 ```java |
| 98 BackgroundTaskScheduleFactory.getScheduler().schedule(myTaskInfo); |
| 99 ``` |
| 100 |
| 101 If you ever need to cancel a task, you can do that by calling `cancel`, and |
| 102 passing in the task ID: |
| 103 |
| 104 ```java |
| 105 BackgroundTaskScheduleFactory.getScheduler().cancel(TaskIds.YOUR_FEATURE); |
| 106 ``` |
| 107 |
| 108 ## Passing task arguments |
| 109 |
| 110 A `TaskInfo` supports passing in arguments through a `Bundle`, but only values |
| 111 that can be part of an Android `BaseBundle` are allowed. You can pass them in |
| 112 using the `TaskInfo.Builder`: |
| 113 |
| 114 ```java |
| 115 Bundle myBundle = new Bundle(); |
| 116 myBundle.putString("foo", "bar"); |
| 117 myBundle.putLong("number", 1337L); |
| 118 |
| 119 TaskInfo.createOneOffTask(TaskIds.YOUR_FEATURE, |
| 120 MyBackgroundTask.class, |
| 121 TimeUnit.MINUTES.toMillis(100) |
| 122 TimeUnit.MINUTES.toMillis(200)) |
| 123 .setExtras(myBundle) |
| 124 .build(); |
| 125 ``` |
| 126 |
| 127 These arguments will be readable for the task through the `TaskParameters` |
| 128 object that is passed to both `onStartTask(...)` and `onStopTask(...)`, by |
| 129 doing the following: |
| 130 |
| 131 ```java |
| 132 boolean onStartTask(Context context, |
| 133 TaskParameters taskParameters, |
| 134 TaskFinishedCallback callback) { |
| 135 Bundle myExtras = taskParameters.getExtras(); |
| 136 // Use |myExtras|. |
| 137 ... |
| 138 } |
| 139 ``` |
| 140 |
| 141 ## Background processing |
| 142 |
| 143 Even though the `BackgroundTaskScheduler` provides functionality for invoking |
| 144 code while the application is in the background, the `BackgroundTask` instance |
| 145 is still invoked on the application main thread. |
| 146 |
| 147 This means that unless the operation is extremely quick, processing must happen |
| 148 asynchronously, and the call to `onStartJob(...)` must return before the task |
| 149 has finished processing. In that case, `onStartJob(...)` must return true, and |
| 150 instead invoke the `TaskFinishedCallback` when the processing is finished, which |
| 151 typically happens on a different `Thread`, `Handler` or using an `AsyncTask`. |
| 152 |
| 153 If the task finishes while still being on the main thread, `onStartJob(...)` |
| 154 should return false, indicating that no further processsing is required. |
| 155 |
| 156 If at any time the constraints given through the `TaskInfo` object does not |
| 157 hold anymore, or if the system deems it necessary, `onStopTask(...)` will be |
| 158 invoked, requiring all activity to cease immediately. The task can return true |
| 159 if the task needs to be rescheduled since it was canceled, or false otherwise. |
| 160 |
| 161 **The system will hold a wakelock from the time `onStartTask(...)` is invoked |
| 162 until either the task itself invokes the `TaskFinishedCallback`, or |
| 163 `onStopTask(...)` is invoked.** |
OLD | NEW |