Trang này giải thích các phương pháp nên dùng để tạo một tiện ích nâng cao hơn nhằm mang lại trải nghiệm tốt hơn cho người dùng.
Tối ưu hoá để cập nhật nội dung tiện ích
Việc cập nhật nội dung tiện ích có thể tốn kém tài nguyên tính toán. Để tiết kiệm pin, hãy tối ưu hoá loại, tần suất và thời gian cập nhật.
Các loại bản cập nhật tiện ích
Có 3 cách để cập nhật một tiện ích: cập nhật toàn bộ, cập nhật một phần và làm mới dữ liệu (trong trường hợp tiện ích tập hợp). Mỗi phương pháp đều có chi phí tính toán và kết quả khác nhau.
Phần sau đây mô tả từng loại nội dung cập nhật và cung cấp đoạn mã cho từng loại.
- Cập nhật đầy đủ: gọi
AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews)để cập nhật đầy đủ tiện ích. Thao tác này sẽ thay thếRemoteViewsđã cung cấp trước đó bằng mộtRemoteViewsmới. Đây là bản cập nhật tốn nhiều tài nguyên tính toán nhất.
val appWidgetManager = AppWidgetManager.getInstance(context) val remoteViews = RemoteViews(context.packageName, R.layout.widgetlayout).apply { setTextViewText(R.id.textview_widget_layout1, "Updated text1") setTextViewText(R.id.textview_widget_layout2, "Updated text2") } appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
- Cập nhật một phần: gọi
AppWidgetManager.partiallyUpdateAppWidgetđể cập nhật các phần của tiện ích. Thao tác này sẽ hợp nhấtRemoteViewsmới vớiRemoteViewsđã cung cấp trước đó. Phương thức này sẽ bị bỏ qua nếu tiện ích không nhận được ít nhất một bản cập nhật đầy đủ thông quaupdateAppWidget(int[], RemoteViews).
val appWidgetManager = AppWidgetManager.getInstance(context) val remoteViews = RemoteViews(context.packageName, R.layout.widgetlayout).apply { setTextViewText(R.id.textview_widget_layout, "Updated text") } appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteViews)
- Làm mới dữ liệu tập hợp: gọi
AppWidgetManager.notifyAppWidgetViewDataChangedđể vô hiệu hoá dữ liệu của một chế độ xem tập hợp trong tiện ích. Thao tác này sẽ kích hoạtRemoteViewsFactory.onDataSetChanged. Trong thời gian chờ đợi, dữ liệu cũ sẽ xuất hiện trong tiện ích. Bạn có thể thực hiện các tác vụ tốn kém một cách đồng bộ bằng phương thức này.
val appWidgetManager = AppWidgetManager.getInstance(context) appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview)
Bạn có thể gọi các phương thức này từ bất cứ đâu trong ứng dụng, miễn là ứng dụng có cùng UID với lớp AppWidgetProvider tương ứng.
Xác định tần suất cập nhật tiện ích
Tiện ích được cập nhật định kỳ tuỳ thuộc vào giá trị được cung cấp cho thuộc tính updatePeriodMillis. Tiện ích có thể cập nhật để phản hồi hoạt động tương tác của người dùng, thông tin cập nhật truyền tin hoặc cả hai.
Cập nhật định kỳ
Bạn có thể kiểm soát tần suất cập nhật định kỳ bằng cách chỉ định một giá trị cho AppWidgetProviderInfo.updatePeriodMillis trong tệp XML appwidget-provider. Mỗi lần cập nhật sẽ kích hoạt phương thức AppWidgetProvider.onUpdate(), đây là nơi bạn có thể đặt mã để cập nhật tiện ích. Tuy nhiên, hãy cân nhắc các giải pháp thay thế cho nội dung cập nhật của bộ nhận tín hiệu truyền tin được mô tả trong phần sau nếu tiện ích của bạn cần tải dữ liệu không đồng bộ hoặc mất hơn 10 giây để cập nhật, vì sau 10 giây, hệ thống sẽ coi BroadcastReceiver là không phản hồi.
updatePeriodMillis không hỗ trợ các giá trị dưới 30 phút. Tuy nhiên, nếu muốn tắt tính năng cập nhật định kỳ, bạn có thể chỉ định 0.
Bạn có thể cho phép người dùng điều chỉnh tần suất cập nhật trong một cấu hình. Ví dụ: họ có thể muốn bảng mã chứng khoán cập nhật 15 phút một lần hoặc chỉ 4 lần một ngày. Trong trường hợp này, hãy đặt updatePeriodMillis thành 0 và sử dụng WorkManager.
Cập nhật để phản hồi một hoạt động tương tác của người dùng
Sau đây là một số cách nên dùng để cập nhật tiện ích dựa trên hoạt động tương tác của người dùng:
Từ một hoạt động của ứng dụng: trực tiếp gọi
AppWidgetManager.updateAppWidgetđể phản hồi một hoạt động tương tác của người dùng, chẳng hạn như một lần nhấn của người dùng.Từ các hoạt động tương tác từ xa, chẳng hạn như thông báo hoặc tiện ích ứng dụng: tạo một
PendingIntent, sau đó cập nhật tiện ích từActivity,BroadcasthoặcServiceđược gọi. Bạn có thể chọn mức độ ưu tiên của riêng mình. Ví dụ: nếu chọnBroadcastchoPendingIntent, bạn có thể chọn foreground broadcast (thông báo trên nền trước) để ưu tiênBroadcastReceiver.
Cập nhật để phản hồi một sự kiện truyền tin
Ví dụ về một sự kiện truyền tin yêu cầu tiện ích cập nhật là khi người dùng chụp ảnh. Trong trường hợp này, bạn nên cập nhật tiện ích khi phát hiện thấy ảnh mới.
Bạn có thể lên lịch công việc bằng WorkManager và chỉ định trình kích hoạt URI nội dung bằng phương thức Constraints.Builder.addContentUriTrigger.
Bạn cũng có thể đăng ký BroadcastReceiver cho thông báo truyền tin, chẳng hạn như nghe ACTION_LOCALE_CHANGED.
Tuy nhiên, vì việc này tiêu tốn tài nguyên thiết bị, hãy sử dụng một cách thận trọng và chỉ nghe thông báo cụ thể. Với việc ra mắt các giới hạn về thông báo truyền phát trong Android 7.0 (cấp độ API 24) và Android 8.0 (cấp độ API 26), các ứng dụng không thể đăng ký thông báo truyền phát ngầm trong tệp kê khai, ngoại trừ một số trường hợp ngoại lệ.
Những điều cần cân nhắc khi cập nhật tiện ích từ BroadcastReceiver
Nếu tiện ích được cập nhật từ BroadcastReceiver, bao gồm cả AppWidgetProvider, hãy lưu ý những điều sau đây về thời lượng và mức độ ưu tiên của bản cập nhật tiện ích.
Thời lượng cập nhật
Theo quy tắc, hệ thống cho phép bộ nhận tín hiệu truyền tin (thường chạy trong luồng chính của ứng dụng) chạy tối đa 10 giây trước khi coi chúng là không phản hồi và kích hoạt lỗi Ứng dụng không phản hồi (ANR). Để tránh chặn luồng chính trong khi xử lý thông báo truyền tin, hãy sử dụng phương thức goAsync. Nếu mất nhiều thời gian hơn để cập nhật tiện ích, hãy cân nhắc việc lên lịch cho một tác vụ bằng WorkManager.
Caution: Any work you do here blocks further broadcasts until it completes,
so it can slow the receiving of later events.
Hãy xem phần Những điều cần lưu ý về bảo mật và các phương pháp hay nhất để biết thêm thông tin.
Mức độ ưu tiên của bản cập nhật
Theo mặc định, các thông báo truyền tin (bao gồm cả những thông báo được thực hiện bằng AppWidgetProvider.onUpdate) sẽ chạy dưới dạng tiến trình nền. Điều này có nghĩa là tài nguyên hệ thống bị quá tải có thể gây ra độ trễ khi gọi bộ nhận tín hiệu truyền tin. Để ưu tiên thông báo, hãy đặt thông báo đó làm quy trình trên nền trước.
Ví dụ: thêm cờ Intent.FLAG_RECEIVER_FOREGROUND vào Intent được truyền đến PendingIntent.getBroadcast khi người dùng nhấn vào một phần nhất định của tiện ích.