1page.title=Tối ưu hóa Chạy ngầm
2page.metaDescription=Các hạn chế mới đối với truyền phát không biểu thị.
3page.keywords="android N", "implicit broadcasts", "job scheduler"
4page.image=images/cards/card-nyc_2x.jpg
5
6@jd:body
7
8<div id="qv-wrapper">
9  <div id="qv">
10    <h2>
11      Trong tài liệu này
12    </h2>
13
14    <ol>
15      <li>
16        <a href="#connectivity-action">Các hạn chế về CONNECTIVITY_ACTION</a>
17      </li>
18
19      <li>
20        <a href="#sched-jobs">Lên lịch Tác vụ Mạng trên Kết nối
21        Không đo lưu lượng</a>
22      </li>
23
24      <li>
25        <a href="#monitor-conn">Theo dõi Kết nối Mạng Trong khi Ứng dụng
26        đang Chạy</a>
27      </li>
28
29      <li>
30        <a href="#media-broadcasts">Các hạn chế về NEW_PICTURE và
31        NEW_VIDEO</a>
32      </li>
33
34      <li>
35        <a href="#new-jobinfo">Các phương thức JobInfo Mới</a>
36      </li>
37
38      <li>
39        <a href="#new-jobparam">Các phương thức JobParameter Mới</a>
40      </li>
41
42      <li>
43        <a href="#further-optimization">Tối ưu hóa thêm Ứng dụng của bạn</a>
44      </li>
45    </ol>
46  </div>
47</div>
48
49<p>
50  Các tiến trình chạy ngầm có thể tiêu tốn bộ nhớ và pin. Ví dụ, một
51  truyền phát không biểu thị có thể bắt đầu nhiều tiến trình chạy ngầm đã đăng ký
52  để theo dõi chúng, ngay cả khi các tiến trình đó có thể không làm việc nhiều. Điều này có thể có
53  ảnh hưởng lớn đến cả hiệu suất của thiết bị lẫn trải nghiệm của người dùng.
54</p>
55
56<p>
57  Để loại bỏ vấn đề này, N Developer Preview áp dụng các hạn chế
58  sau:
59</p>
60
61<ul>
62  <li>Các ứng dụng nhắm đến Preview không nhận được truyền phát {@link
63  android.net.ConnectivityManager#CONNECTIVITY_ACTION} nếu chúng
64  đăng ký nhận truyền phát trong bản kê khai của chúng. Các ứng dụng đang chạy ở tiền cảnh
65  vẫn có thể theo dõi {@code CONNECTIVITY_CHANGE} trên luồng chính của chúng bằng cách
66  đăng ký{@link android.content.BroadcastReceiver} với {@link
67  android.content.Context#registerReceiver Context.registerReceiver()}.
68  </li>
69
70  <li>Ứng dụng không thể gửi hoặc nhận các truyền phát {@link
71  android.hardware.Camera#ACTION_NEW_PICTURE} hoặc {@link
72  android.hardware.Camera#ACTION_NEW_VIDEO}. Việc tối ưu này
73  tác động đến mọi ứng dụng, không chỉ các ứng dụng nhắm đến Preview.
74  </li>
75</ul>
76
77<p>
78  Khuôn khổ Android cung cấp một số giải pháp để giảm thiểu sự cần thiết đối với
79  các truyền phát không biểu thị. Ví dụ, {@link android.app.job.JobScheduler}
80  và <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
81  {@code GcmNetworkManager}</a> cung cấp một cơ chế lên lịch hiệu quả
82  cho các hoạt động mạng khi đáp ứng các điều kiện được chỉ định, ví dụ như kết nối tới mạng
83 không đo lưu lượng. Bây giờ bạn cũng có thể sử dụng {@link android.app.job.JobScheduler}
84  để phản ứng lại với các thay đổi đối với các trình cung cấp nội dung. Các đối tượng {@link android.app.job.JobInfo}
85  gói gọn các tham số {@link android.app.job.JobScheduler}
86  dùng để lên lịch tác vụ của bạn. Khi đáp ứng được các điều kiện của tác vụ, hệ thống
87  sẽ thực thi tác vụ này trên {@link android.app.job.JobService} của ứng dụng của bạn.
88</p>
89
90<p>
91  Trong tài liệu này, chúng ta sẽ tìm hiểu cách sử dụng các phương thức thay thế, chẳng hạn như
92  {@link android.app.job.JobScheduler}, để thích ứng ứng dụng của bạn với các hạn chế
93  mới này.
94</p>
95
96<h2 id="connectivity-action">
97  Các hạn chế về CONNECTIVITY_ACTION
98</h2>
99
100<p>
101  Các ứng dụng nhắm đến N Developer Preview không nhận được truyền phát {@link
102  android.net.ConnectivityManager#CONNECTIVITY_ACTION} nếu chúng
103  đăng ký nhận truyền phát trong bản kê khai của chúng, và các tiến trình phụ thuộc vào truyền phát này
104  sẽ không khởi động. Điều này cũng đặt ra một vấn đề cho ứng dụng
105  về việc theo dõi thay đổi mạng hoặc thực hiện các hoạt động mạng hàng loạt khi
106  thiết bị kết nối với một mạng không đo lưu lượng. Một số giải pháp để tránh khỏi hạn chế này
107  đã tồn tại trong khuôn khổ Android, nhưng chọn được một giải pháp phù hợp
108  phụ thuộc vào những gì bạn muốn ứng dụng của bạn hoàn thành.
109</p>
110
111<p class="note">
112  <strong>Lưu ý:</strong> Một{@link android.content.BroadcastReceiver} có đăng ký
113  {@link android.content.Context#registerReceiver Context.registerReceiver()}
114  tiếp tục nhận các truyền phát này trong khi ứng dụng đang ở tiền cảnh.
115</p>
116
117<h3 id="sched-jobs">
118  Lên lịch Tác vụ Mạng trên Kết nối Không đo lưu lượng
119</h3>
120
121<p>
122  Khi sử dụng lớp{@link android.app.job.JobInfo.Builder JobInfo.Builder}
123  để xây dựng đối tượng {@link android.app.job.JobInfo} của bạn, hãy áp dụng phương thức {@link
124  android.app.job.JobInfo.Builder#setRequiredNetworkType
125  setRequiredNetworkType()} và chuyển {@link android.app.job.JobInfo
126  JobInfo.NETWORK_TYPE_UNMETERED} dưới dạng một tham số tác vụ. Đoạn mã mẫu sau
127  lên lịch một dịch vụ để chạy khi thiết bị kết nối với một mạng
128  không đo lưu lượng và đang sạc:
129</p>
130
131<pre>
132public static final int MY_BACKGROUND_JOB = 0;
133...
134public static void scheduleJob(Context context) {
135  JobScheduler js =
136      (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
137  JobInfo job = new JobInfo.Builder(
138    MY_BACKGROUND_JOB,
139    new ComponentName(context, MyJobService.class))
140      .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
141      .setRequiresCharging(true)
142      .build();
143  js.schedule(job);
144}
145</pre>
146
147<p>
148  Khi các điều kiện cho tác vụ của bạn đã được đáp ứng, ứng dụng của bạn sẽ nhận được lệnh gọi lại để chạy
149  phương thức{@link android.app.job.JobService#onStartJob onStartJob()}trong
150  {@code JobService.class} được chỉ định. Để xem thêm các ví dụ về triển khai {@link
151  android.app.job.JobScheduler} , hãy xem <a href="{@docRoot}samples/JobScheduler/index.html">ứng dụng mẫu JobScheduler</a>.
152</p>
153
154<p>
155  Các ứng dụng sử dụng dịch vụ GMSCore, và nhắm đến Android 5.0 (API mức 21)
156  hoặc thấp hơn, có thể sử dụng <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
157  {@code GcmNetworkManager}</a> và quy định {@code Task.NETWORK_STATE_UNMETERED}.
158</p>
159
160<h3 id="monitor-conn">
161  Theo dõi Kết nối Mạng Trong khi Ứng dụng đang Chạy
162</h3>
163
164<p>
165  Các ứng dụng đang chạy ở tiền cảnh vẫn có thể theo dõi {@code
166  CONNECTIVITY_CHANGE} bằng một{@link
167  android.content.BroadcastReceiver} đã đăng ký. Tuy nhiên, API {@link
168  android.net.ConnectivityManager} cung cấp phương thức yêu cầu lệnh gọi lại hiệu quả hơn
169  chỉ khi đáp ứng được các điều kiện được chỉ định.
170</p>
171
172<p>
173  Các đối tượng {@link android.net.NetworkRequest} định nghĩa các tham số của
174  lệnh gọi lại mạng xét về  {@link android.net.NetworkCapabilities}. Bạn
175  tạo các đối tượng {@link android.net.NetworkRequest} bằng lớp {@link
176  android.net.NetworkRequest.Builder NetworkRequest.Builder}. {@link
177  android.net.ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest,
178  android.net.ConnectivityManager.NetworkCallback) registerNetworkCallback()}
179  rồi chuyển đối tượng{@link android.net.NetworkRequest} sang hệ thống. Khi
180  đáp ứng được các điều kiện mạng, ứng dụng nhận lệnh gọi lại để thực thi phương thức
181  {@link android.net.ConnectivityManager.NetworkCallback#onAvailable
182  onAvailable()} như được định nghĩa trong lớp {@link
183  android.net.ConnectivityManager.NetworkCallback} của nó.
184</p>
185
186<p>
187  Ứng dụng tiếp tục nhận lệnh gọi lại cho đến khi ứng dụng tồn tại hoặc nó gọi
188  {@link android.net.ConnectivityManager#unregisterNetworkCallback
189  unregisterNetworkCallback()}.
190</p>
191
192<h2 id="media-broadcasts">
193  Các hạn chế về NEW_PICTURE và NEW_VIDEO
194</h2>
195
196<p>
197  Trong N Developer Preview, ứng dụng không thể gửi hoặc nhận các truyền phát {@link
198  android.hardware.Camera#ACTION_NEW_PICTURE} hoặc {@link
199  android.hardware.Camera#ACTION_NEW_VIDEO}. Hạn chế này giúp
200  loại bỏ các tác động về hiệu suất và trải nghiệm của người dùng khi một số ứng dụng phải
201  thức dậy để xử lý một ảnh hoặc video mới. N Developer Preview
202  mở rộng {@link android.app.job.JobInfo} và {@link
203  android.app.job.JobParameters} để cung cấp một giải pháp thay thế.
204</p>
205
206<h3 id="new-jobinfo">
207  Các phương thức JobInfo Mới
208</h3>
209
210<p>
211  Để kích hoạt tác vụ khi thay đổi URI nội dung, N Developer Preview sẽ mở rộng
212  API{@link android.app.job.JobInfo} bằng các phương thức sau:
213</p>
214
215<dl>
216  <dt>
217    {@code JobInfo.TriggerContentUri()}
218  </dt>
219
220  <dd>
221    Gói gọn các tham số yêu cầu để kích hoạt tác vụ khi thay đổi URI nội dung.
222  </dd>
223
224  <dt>
225    {@code JobInfo.Builder.addTriggerContentUri()}
226  </dt>
227
228  <dd>
229    Chuyển một đối tượng {@code TriggerContentUri} đến {@link
230    android.app.job.JobInfo}. Một {@link android.database.ContentObserver}
231    sẽ theo dõi URI nội dung được gói gọn. Nếu có nhiều đối tượng {@code
232    TriggerContentUri} được liên kết với một tác vụ, hệ thống sẽ cung cấp
233    lệnh gọi lại ngay cả khi hệ thống báo cáo có sự thay đổi chỉ ở trong một trong những URI nội dung.
234  </dd>
235
236  <dd>
237    Thêm cờ {@code TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS} để
238    kích hoạt tác vụ nếu bất kỳ kế nhiệm nào của URI đã cho thay đổi. Cờ này
239    tương ứng với tham số {@code notifyForDescendants} đã chuyển đến {@link
240    android.content.ContentResolver#registerContentObserver
241    registerContentObserver()}.
242  </dd>
243</dl>
244
245<p class="note">
246  <strong>Lưu ý:</strong> {@code TriggerContentUri()} không thể được sử dụng
247  kết hợp với {@link android.app.job.JobInfo.Builder#setPeriodic
248  setPeriodic()} hoặc {@link android.app.job.JobInfo.Builder#setPersisted
249  setPersisted()}. Để tiếp tục theo dõi các thay đổi nội dung, hãy lên lịch một
250  {@link android.app.job.JobInfo} mới trước khi {@link
251  android.app.job.JobService} của ứng dụng hoàn thành xử lý lệnh gọi lại gần đây nhất.
252</p>
253
254<p>
255  Đoạn mã mẫu sau lên lịch kích hoạt một tác vụ khi hệ thống báo cáo
256  có sự thay đổi về URI nội dung, {@code MEDIA_URI}:
257</p>
258
259<pre>
260public static final int MY_BACKGROUND_JOB = 0;
261...
262public static void scheduleJob(Context context) {
263  JobScheduler js =
264          (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
265  JobInfo.Builder builder = new JobInfo.Builder(
266          MY_BACKGROUND_JOB,
267          new ComponentName(context, MediaContentJob.class));
268  builder.addTriggerContentUri(
269          new JobInfo.TriggerContentUri(MEDIA_URI,
270          JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
271  js.schedule(builder.build());
272}
273</pre>
274<p>
275  Khi hệ thống báo cáo có sự thay đổi trong (các) URI nội dung được chỉ định, ứng dụng của bạn
276  sẽ nhận được lệnh gọi lại và một đối tượng {@link android.app.job.JobParameters} được chuyển sang
277  phương thức {@link android.app.job.JobService#onStartJob onStartJob()}
278  trong {@code MediaContentJob.class}.
279</p>
280
281<h3 id="new-jobparam">
282  Các phương thức JobParameter Mới
283</h3>
284
285<p>
286  N Developer Preview cũng mở rộng {@link android.app.job.JobParameters} để
287  cho phép ứng dụng của bạn nhận thông tin hữu ích về những gì thẩm quyền nội dung
288  và các URI đã kích hoạt tác vụ:
289</p>
290
291<dl>
292  <dt>
293    {@code Uri[] getTriggeredContentUris()}
294  </dt>
295
296  <dd>
297    Trả về mảng URI đã kích hoạt tác vụ đó. Kết quả trả về có thể bằng {@code
298    null} nếu không có URI nào kích hoạt  tác vụ (ví dụ như, tác vụ đã được
299    kích hoạt do thời hạn hoặc lý do khác), hoặc số các URI
300    bị thay đổi nhiều hơn 50.
301  </dd>
302
303  <dt>
304    {@code String[] getTriggeredContentAuthorities()}
305  </dt>
306
307  <dd>
308    Trả về mảng xâu thẩm quyền nội dung đã kích hoạt tác vụ đó.
309    Nếu mảng được trả về không phải {@code null}, hãy dùng {@code getTriggeredContentUris()}
310    để truy xuất chi tiết về URI nào đã thay đổi.
311  </dd>
312</dl>
313
314<p>
315  Mã mẫu sau sẽ ghi đè lên phương thức {@link
316  android.app.job.JobService#onStartJob JobService.onStartJob()} và
317  và ghi lại các thẩm quyền nội dung và URI đã kích hoạt tác vụ.
318</p>
319
320<pre>
321&#64;Override
322public boolean onStartJob(JobParameters params) {
323  StringBuilder sb = new StringBuilder();
324  sb.append("Media content has changed:\n");
325  if (params.getTriggeredContentAuthorities() != null) {
326      sb.append("Authorities: ");
327      boolean first = true;
328      for (String auth :
329          params.getTriggeredContentAuthorities()) {
330          if (first) {
331              first = false;
332          } else {
333             sb.append(", ");
334          }
335           sb.append(auth);
336      }
337      if (params.getTriggeredContentUris() != null) {
338          for (Uri uri : params.getTriggeredContentUris()) {
339              sb.append("\n");
340              sb.append(uri);
341          }
342      }
343  } else {
344      sb.append("(No content)");
345  }
346  Log.i(TAG, sb.toString());
347  return true;
348}
349</pre>
350
351<h2 id="further-optimization">
352  Tối ưu hóa thêm Ứng dụng của bạn
353</h2>
354
355<p>
356  Tối ưu hóa ứng dụng của bạn để chạy trên các thiết bị có bộ nhớ ít, hoặc đang trong điều kiện
357  bộ nhớ ít có thể cải thiện hiệu suất và trải nghiệm của người dùng. Loại bỏ
358  các thành phần phụ thuộc trên các dịch vụ chạy ngầm và bộ thu truyền phát không biểu thị đã đăng ký tĩnh
359  có thể giúp ứng dụng của bạn chạy tốt hơn trên các thiết bị như vậy. Mặc dù
360  N Developer Preview thực hiện các bước để giảm bớt một vài trong số các vấn đề này, nhưng chúng tôi
361  khuyến nghị bạn nên tối ưu ứng dụng của bạn để chạy hoàn toàn không cần sử dụng
362  các tiến trình chạy ngầm này.
363</p>
364
365<p>
366  N Developer Preview giới thiệu một số lệnh <a href="{@docRoot}tools/help/adb.html">Android Debug Bridge (ADB)</a> bổ sung mà
367  bạn có thể sử dụng để kiểm thử hành vi của ứng dụng bằng các tiến trình chạy ngầm đã bị vô hiệu hóa đó:
368</p>
369
370<ul>
371  <li>Để mô phỏng các điều kiện trong đó các truyền phát không biểu thị và dịch vụ chạy ngầm
372  không có sẵn, hãy nhập lệnh sau:
373  </li>
374
375  <li style="list-style: none; display: inline">
376<pre class="no-pretty-print">
377{@code $ adb shell cmd appops set RUN_IN_BACKGROUND ignore}
378</pre>
379  </li>
380
381  <li>Để kích hoạt lại các truyền phát không biểu thị và dịch vụ chạy ngầm, hãy nhập
382  lệnh sau:
383  </li>
384
385  <li style="list-style: none; display: inline">
386<pre class="no-pretty-print">
387{@code $ adb shell cmd appops set RUN_IN_BACKGROUND allow}
388</pre>
389  </li>
390</ul>