Hạn chế của hệ thống đối với công việc ở chế độ nền

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 nhiều. Điều 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 API phù hợp 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 ứng dụng thể hiện một số hành vi xấu được mô tả trong Android vitals, 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, hệ thống sẽ thông báo cho người dùng và cho phép người dùng 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:

  1. Quá nhiều lần khoá chế độ thức: 1 khoá chế độ thức một phần bị giữ trong vòng một giờ khi màn hình tắt
  2. 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, trừ phi ứng dụng đó chạy ở 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 sẽ 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à các 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 các thay đổi về mạng hoặc thực hiện các hoạt động mạng hàng loạt khi thiết bị kết nối với một mạng không đo lượng dữ liệu. Hiện đã có một số giải pháp để khắc phục quy định hạn chế này trong khung Android, nhưng việc chọn giải pháp phù hợp phụ thuộc vào những gì bạn muốn ứng dụng của mình đạt được.

Lên lịch 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 đáp ứng các điều kiện cho công việc, ứng dụng 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 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 đáp ứng các điều kiện mạng đã chỉ định.

Đối tượng NetworkRequest xác định các tham số của lệnh gọi lại mạng theo NetworkCapabilities. Bạn tạo các đối tượng NetworkRequest bằng lớp NetworkRequest.Builder. registerNetworkCallback sau đó truyền đối tượng NetworkRequest đến hệ thống. Khi các điều kiện mạng được đáp ứ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 cá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 tác động đến hiệu suất 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 xem tổ chức phát hành nội dung nào đã kích hoạt tác vụ

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 tác vụ đó:

List<Uri> getTriggeredContentUris()

Trả về danh sách URI đã kích hoạt công việc. Giá trị này trống nếu không có URI nào kích hoạt tác vụ (chẳng hạn như tác vụ đã đượ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 gồm những 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 sử dụng getTriggeredContentUris() để truy xuất thông tin chi tiết về các 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:

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 theo các hạn chế về 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à broadcast receiver 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 hoàn toàn sử dụng các quy trình nền này.

Một số lệnh Cầu gỡ lỗi Android (ADB) bổ sung có thể giúp bạn kiểm thử hành vi của ứng dụng khi các quy trình nền đó đã tắt:

  • Để mô phỏng các điều kiện 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 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 các cách hay khác giúp tối ưu hoá hành vi của tác vụ trong nền, hãy xem tài liệu Tối ưu hoá mức sử dụng pin cho API lên lịch tác vụ.