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@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>