Chromium Code Reviews| 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 isonly used when the system API is not | |
|
David Trainor- moved to gerrit
2017/02/24 07:19:46
isonly -> is only
nyquist
2017/02/24 23:41:11
Done.
| |
| 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 | |
|
David Trainor- moved to gerrit
2017/02/24 07:19:47
Should we assert this at register time?
nyquist
2017/02/24 23:41:11
Done.
| |
| 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(42, | |
|
nyquist
2017/02/22 18:24:12
Self-review: Change to use TaskIds.YOUR_FEATURE
nyquist
2017/02/24 23:41:11
Done.
| |
| 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(42, | |
| 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(42, | |
| 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(42); | |
| 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); | |
|
Peter Beverloo
2017/02/24 18:07:09
This is awesome, no more Bundle/PersistableBundle
nyquist
2017/02/24 23:41:11
Yeah, at least we only have to write that horrible
| |
| 118 | |
| 119 TaskInfo.createOneOffTask(42, | |
| 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`. | |
|
Peter Beverloo
2017/02/24 18:07:08
What if a feature cannot invoke yet TaskFinishedCa
nyquist
2017/02/24 23:41:11
That would be something we have to think about I b
| |
| 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 |