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 |