Các quy trình trong nền có thể tốn nhiều bộ nhớ và pin. Ví dụ: một thông báo truyền phát ngầm có thể bắt đầu nhiều quy trình nền đã đăng ký để theo dõi thông báo đó, ngay cả khi các quy trình đó có thể không hoạt động hiệu quả. Việc này có thể có tác động đáng kể đến cả hiệu suất của thiết bị và trải nghiệm người dùng.
Để tránh các hạn chế của hệ thống, hãy đảm bảo bạn sử dụng đúng API cho tác vụ ở chế độ nền. Tài liệu Tổng quan về tác vụ trong nền giúp bạn chọn API phù hợp với nhu cầu của mình.
Các hạn chế do người dùng khởi tạo
Nếu một ứng dụng thể hiện một số hành vi xấu được mô tả trong Android vitals, thì hệ thống sẽ nhắc người dùng hạn chế quyền truy cập của ứng dụng đó vào tài nguyên hệ thống.
Nếu nhận thấy một ứng dụng đang sử dụng quá nhiều tài nguyên, thì hệ thống sẽ thông báo cho người dùng và cho phép người dùng lựa chọn hạn chế các hành động của ứng dụng. Những hành vi có thể kích hoạt thông báo bao gồm:
- Quá nhiều lần khoá chế độ thức: 1 phần khoá chế độ thức bị giữ trong một giờ khi màn hình tắt
- Dịch vụ nền quá mức: Nếu ứng dụng nhắm đến các cấp độ API thấp hơn 26 và có quá nhiều dịch vụ nền
Các hạn chế chính xác do nhà sản xuất thiết bị quyết định. Ví dụ: trên các bản dựng AOSP, các ứng dụng bị hạn chế không thể chạy công việc, kích hoạt chuông báo hoặc sử dụng mạng, ngoại trừ khi ứng dụng chạy trên nền trước.
Quy định hạn chế đối với việc nhận thông báo về hoạt động mạng
Các ứng dụng không nhận được thông báo CONNECTIVITY_ACTION nếu đăng ký nhận các thông báo đó trong tệp kê khai, và những quy trình phụ thuộc vào thông báo này sẽ không bắt đầu. Điều này có thể gây ra vấn đề cho các ứng dụng muốn theo dõi những thay đổi mạng hoặc thực hiện hoạt động hàng loạt trên mạng khi thiết bị kết nối với một mạng không đo lượng dữ liệu. Đã có sẵn một số giải pháp để khắc phục vấn đề hạn chế này trong khung Android, nhưng việc chọn giải pháp phù hợp sẽ tuỳ thuộc vào việc bạn muốn ứng dụng của mình đạt được điều gì.
Lên lịch cho công việc trên các kết nối không đo lượng dữ liệu
Khi tạo WorkRequest, hãy thêm NetworkType.UNMETERED Constraint.
fun scheduleWork(context: Context) {
val workManager = WorkManager.getInstance(context)
val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.build()
)
.build()
workManager.enqueue(workRequest)
}
Khi các điều kiện cho công việc 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 phương thức doWork() trong lớp Worker được chỉ định.
Giám sát khả năng kết nối mạng trong khi ứng dụng đang chạy
Các ứng dụng đang chạy vẫn có thể theo dõi CONNECTIVITY_CHANGE bằng một BroadcastReceiver đã đăng ký. Tuy nhiên, API ConnectivityManager cung cấp một phương thức mạnh mẽ hơn để chỉ yêu cầu gọi lại khi các điều kiện mạng đã chỉ định được đáp ứng.
Các đối tượng NetworkRequest xác định các tham số của lệnh gọi lại mạng về phương diện NetworkCapabilities. Bạn tạo các đối tượng NetworkRequest bằng lớp NetworkRequest.Builder. registerNetworkCallback sau đó chuyển đối tượng NetworkRequest đến hệ thống. Khi đã đáp ứng được các điều kiện mạng, ứng dụng sẽ nhận được lệnh gọi lại để thực thi phương thức onAvailable() được xác định trong lớp ConnectivityManager.NetworkCallback.
Ứng dụng sẽ tiếp tục nhận được lệnh gọi lại cho đến khi ứng dụng thoát hoặc gọi unregisterNetworkCallback().
Quy định hạn chế đối với việc nhận thông báo về hình ảnh và video
Các ứng dụng không thể gửi hoặc nhận thông báo ACTION_NEW_PICTURE hoặc ACTION_NEW_VIDEO. Quy định hạn chế này giúp giảm bớt hiệu quả hoạt động và trải nghiệm người dùng khi một số ứng dụng phải đánh thức để xử lý hình ảnh hoặc video mới.
Xác định tổ chức phát hành nội dung nào đã kích hoạt công việc
WorkerParameters cho phép ứng dụng của bạn nhận thông tin hữu ích về những tổ chức phát hành nội dung và URI nào đã kích hoạt công việc này:
List<Uri> getTriggeredContentUris()
Trả về danh sách các URI đã kích hoạt công việc. Đây là một chuỗi trống nếu không có URI nào kích hoạt lệnh (chẳng hạn như lệnh đã được kích hoạt do có thời hạn hoặc vì một số lý do khác), hoặc số URI thay đổi lớn hơn 50.
List<String> getTriggeredContentAuthorities()
Trả về danh sách chuỗi của tổ chức phát hành nội dung đã kích hoạt công việc. Nếu danh sách được trả về không trống, hãy dùng getTriggeredContentUris() để truy xuất thông tin chi tiết về những URI đã thay đổi.
Mã mẫu sau đây ghi đè phương thức CoroutineWorker.doWork() và ghi lại các tổ chức phát hành nội dung và URI đã kích hoạt lệnh này:
class MyWorker(
appContext: Context,
params: WorkerParameters
): CoroutineWorker(appContext, params)
override suspend fun doWork(): Result {
StringBuilder().apply {
append("Media content has changed:\n")
params.triggeredContentAuthorities
.takeIf { it.isNotEmpty() }
?.let { authorities ->
append("Authorities: ${authorities.joinToString(", ")}\n")
append(params.triggeredContentUris.joinToString("\n"))
} ?: append("(No content)")
Log.i(TAG, toString())
}
return Result.success()
}
}
Kiểm thử ứng dụng trong các quy định hạn chế của hệ thống
Việc tối ưu hoá ứng dụng để chạy trên các thiết bị có bộ nhớ thấp hoặc trong điều kiện bộ nhớ thấp có thể giúp cải thiện hiệu suất và trải nghiệm người dùng. Việc xoá các phần phụ thuộc trên dịch vụ nền và thông báo truyền phát ngầm đã đăng ký tệp kê khai 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. Bạn nên tối ưu hoá ứng dụng để chạy mà không cần sử dụng toàn bộ các quy trình trong nền này.
Một số lệnh Cầu gỡ lỗi Android (ADB) khác có thể giúp bạn kiểm thử hành vi của ứng dụng khi các quy trình trong nền đó bị tắt:
Để mô phỏng các điều kiện mà không có thông báo truyền phát ngầm cũng như dịch vụ nền, hãy nhập lệnh sau:
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignoreĐể bật lại các thông báo truyền phát ngầm và dịch vụ nền, hãy nhập lệnh sau:
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow
Tối ưu hoá hơn nữa ứng dụng của bạn
Để biết những cách hay khác giúp tối ưu hoá hành vi của các tác vụ ở chế độ nền, hãy xem tài liệu Tối ưu hoá mức sử dụng pin cho các API lập lịch tác vụ.