Permission Handler trong Android: cách hoạt động, xử lý yêu cầu và triển khai

Tác giả: IT Sectr Đã đăng: 2026-05-20 Thời gian đọc: 8 phút

Permission Handler là một thành phần ứng dụng Android chịu trách nhiệm kiểm tra, yêu cầu và xử lý kết quả của các quyền runtime. Theo Android Developer Guide, 2024, một trình xử lý quyền tập trung hóa logic của checkSelfPermission, requestPermissions và shouldShowRequestPermissionRationale trong một lớp hoặc ViewModel duy nhất. Điều này đơn giản hóa việc bảo trì mã và cải thiện kiểm thử.

Những điểm chính

  • Permission Handler — một thành phần chuyên biệt để quản lý tập trung các quyền runtime Android.
  • Đóng gói logic của checkSelfPermission, requestPermissions và shouldShowRequestPermissionRationale.
  • Các triển khai hiện đại dựa trên ActivityResultContracts từ androidx.activity.
  • Đơn giản hóa kiểm thử đơn vị nhờ đảo ngược phụ thuộc và cô lập mã nền tảng.
  • Các thực hành tốt nhất bao gồm một handler duy nhất cho mỗi Activity và tái sử dụng qua vùng chứa DI.

Permission Handler trong Android là gì

Permission Handler là một mẫu kiến trúc để quản lý tập trung các quyền runtime Android. Thay vì các lời gọi rải rác đến ContextCompat.checkSelfPermission và ActivityCompat.requestPermissions khắp mã ứng dụng, tất cả logic xử lý yêu cầu và kết quả được tập trung trong một lớp duy nhất. Điều này giảm sự trùng lặp, đơn giản hóa bảo trì và làm cho mã dễ dự đoán hơn.

Sự cần thiết của Permission Handler xuất hiện cùng với việc giới thiệu quyền runtime trong Android 6.0. Trước đó, tất cả quyền được yêu cầu khi cài đặt và mã ứng dụng có thể sử dụng bất kỳ API nào mà không cần kiểm tra. Sau khi chuyển sang mô hình runtime, mỗi lần sử dụng quyền nguy hiểm đều yêu cầu kiểm tra ba bước: checkSelfPermission, requestPermissions, onRequestPermissionsResult. Phân tán logic này qua Activity và Fragment dẫn đến trùng lặp nội dòng và lỗi. Theo Google I/O 2019, tập trung hóa xử lý quyền giảm số lượng lỗi liên quan đến Permission Denial trung bình 60 phần trăm.

Một Permission Handler tốt cung cấp giao diện sạch cho mã gọi. Activity hoặc Fragment không cần biết chi tiết của yêu cầu — chúng gọi một phương thức như requestCamera(callback), và handler tự quản lý việc kiểm tra trạng thái, hiển thị giải thích, gọi hộp thoại hệ thống và chuyển kết quả đến callback. Điều này thực hiện nguyên tắc trách nhiệm đơn lẻ và tách biệt logic kinh doanh khỏi mã quyền nền tảng.

Khi nào cần Permission Handler

Permission Handler trở nên cần thiết khi ứng dụng sử dụng 3 quyền nguy hiểm trở lên. Đối với ứng dụng đơn giản với một quyền (ví dụ: camera cho máy quét mã QR), lời gọi trực tiếp có thể đủ. Nhưng đối với ứng dụng di động điển hình với camera, định vị, thông báo và bộ nhớ — một trình xử lý tập trung là cần thiết để bảo trì.

Kiến trúc của Permission Handler

Một Permission Handler điển hình bao gồm ba lớp: một hợp đồng giao diện, một triển khai với ActivityResultLauncher và một lớp ViewModel. Giao diện định nghĩa các phương thức yêu cầu cho mỗi quyền — requestCamera, requestLocation, requestStorage. Triển khai liên kết các phương thức này với các hợp đồng ActivityResultContracts.RequestPermission tương ứng.

Các thành phần kiến trúc chính:

  • PermissionHandlerContract — một giao diện với các phương thức cho mỗi quyền
  • PermissionHandlerImpl — một triển khai kết nối với ActivityResultRegistry
  • PermissionResult — một lớp sealed với các trạng thái GRANTED, DENIED, NEVER_ASK_AGAIN
  • RationaleHandler — một thành phần để hiển thị giải thích trước yêu cầu

Kiến trúc này cho phép dễ dàng hoán đổi các triển khai trong kiểm thử: thay vì ActivityResultLauncher thực, một mock trả về kết quả định trước mà không tương tác với hệ thống. Điều này rất quan trọng cho kiểm thử đơn vị logic UI, nơi không thể khởi chạy Activity cho hộp thoại quyền.

Quản lý vòng đời

Permission Handler phải tính đến vòng đời của Activity và Fragment. Các trình khởi chạy được đăng ký trong ActivityResultRegistry, tự động lưu và khôi phục trạng thái khi xoay màn hình và tạo lại Activity. Handler không nên lưu trữ tham chiếu trực tiếp đến Activity hoặc Fragment — thay vào đó, hãy sử dụng WeakReference hoặc truyền registry qua hàm tạo. Điều này ngăn rò rỉ bộ nhớ và sự cố khi thay đổi cấu hình.

Triển khai Permission Handler trong Kotlin

Một triển khai cơ bản của Permission Handler được xây dựng trên ActivityResultContracts.RequestPermission. Handler nhận ActivityResultRegistry từ ComponentActivity hoặc Fragment và đăng ký các trình khởi chạy cho mỗi quyền. Mỗi trình khởi chạy chấp nhận một lambda callback được gọi sau khi người dùng phản hồi.

kotlin
sealed class PermissionResult {
    object GRANTED : PermissionResult()
    data class DENIED(
        val shouldShowRationale: Boolean
    ) : PermissionResult()
}

interface PermissionHandler {
    fun requestCamera(
        callback: (PermissionResult) -> Unit
    )
    fun requestLocation(
        callback: (PermissionResult) -> Unit
    )
    fun isPermissionGranted(
        permission: String
    ): Boolean
}

class AndroidPermissionHandler(
    private val registry: ActivityResultRegistry,
    private val context: Context
) : PermissionHandler {

    private var cameraLauncher: ActivityResultLauncher<String>? = null

    fun initialize() {
        cameraLauncher = registry.register(
            "camera_permission",
            ActivityResultContracts.RequestPermission()
        ) { isGranted ->
            if (isGranted) {
                pendingCameraCallback?.invoke(
                    PermissionResult.GRANTED
                )
            } else {
                val rationale = ActivityCompat.shouldShowRequestPermissionRationale(
                    context as Activity,
                    Manifest.permission.CAMERA
                )
                pendingCameraCallback?.invoke(
                    PermissionResult.DENIED(rationale)
                )
            }
        }
    }

    private var pendingCameraCallback:
        ((PermissionResult) -> Unit)? = null

    override fun requestCamera(
        callback: (PermissionResult) -> Unit
    ) {
        if (isPermissionGranted(
                Manifest.permission.CAMERA
        )) {
            callback.invoke(PermissionResult.GRANTED)
            return
        }
        pendingCameraCallback = callback
        cameraLauncher?.launch(
            Manifest.permission.CAMERA
        )
    }

    override fun isPermissionGranted(
        permission: String
    ): Boolean {
        return ContextCompat.checkSelfPermission(
            context, permission
        ) == PackageManager.PERMISSION_GRANTED
    }
}

Khởi tạo trong Activity

Handler được khởi tạo trong onCreate của Activity qua registerForActivityResult, cung cấp quyền truy cập vào ActivityResultRegistry. Sau khi khởi tạo, handler sẵn sàng xử lý các yêu cầu trong suốt vòng đời của Activity. Điều quan trọng là gọi initialize trước yêu cầu đầu tiên, nếu không trình khởi chạy sẽ không được đăng ký.

Permission Handler với ViewModel

Tích hợp Permission Handler với ViewModel là cách tiếp cận tiên tiến nhất. ViewModel quản lý trạng thái yêu cầu, trong khi Handler chỉ thực hiện các lời gọi nền tảng. ViewModel chứa StateFlow<PermissionUiState>, trong đó UiState mô tả quyền nào đang được yêu cầu và kết quả nào đã được nhận. Activity đăng ký StateFlow này và ủy quyền yêu cầu cho Handler.

kotlin
class PermissionsViewModel : ViewModel() {

    private val _uiState =
        MutableStateFlow<PermissionUiState>(
            PermissionUiState.Idle
        )
    val uiState: StateFlow<PermissionUiState> = _uiState.asStateFlow()

    fun onCameraRequested() {
        _uiState.value = PermissionUiState.RequestingCamera
    }

    fun onPermissionResult(
        permission: String,
        result: PermissionResult
    ) {
        when (result) {
            PermissionResult.GRANTED -> {
                _uiState.value = PermissionUiState.Granted(permission)
            }
            is PermissionResult.DENIED -> {
                _uiState.value = PermissionUiState.Denied(
                    permission,
                    result.shouldShowRationale
                )
            }
        }
    }
}

sealed class PermissionUiState {
    object Idle : PermissionUiState()
    object RequestingCamera : PermissionUiState()
    data class Granted(val permission: String) : PermissionUiState()
    data class Denied(
        val permission: String,
        val shouldShowRationale: Boolean
    ) : PermissionUiState()
}

Trong mô hình này, Activity kiểm tra isPermissionGranted qua Handler khi khởi động, trong khi ViewModel chỉ quản lý trạng thái. Nếu quyền chưa được cấp — Activity đăng ký uiState, gọi requestCamera từ Handler và chuyển kết quả trở lại ViewModel qua onPermissionResult. Tách mã nền tảng khỏi logic kinh doanh cho phép kiểm thử ViewModel mà không cần phụ thuộc Android.

Kiểm thử Permission Handler

Kiểm thử đơn vị Permission Handler có thể thực hiện nhờ giao diện PermissionHandler. Trong kiểm thử, một FakePermissionHandler được tạo ra để mô phỏng các kịch bản khác nhau: quyền được cấp, bị từ chối, Never Ask Again. Mỗi kịch bản được kiểm thử độc lập. Điều này đặc biệt quan trọng để kiểm thử logic UI phải phản ứng chính xác với cả ba kết quả.

kotlin
class FakePermissionHandler : PermissionHandler {

    var cameraResult: PermissionResult =
        PermissionResult.GRANTED
    var grantedPermissions: Set<String> =
        setOf(Manifest.permission.CAMERA)

    override fun requestCamera(
        callback: (PermissionResult) -> Unit
    ) {
        callback.invoke(cameraResult)
    }

    override fun isPermissionGranted(
        permission: String
    ): Boolean {
        return permission in grantedPermissions
    }
}

Triển khai giả cho phép kiểm thử ViewModel mà không cần trình giả lập. Chỉ cần đặt cameraResult thành giá trị mong muốn và xác minh rằng ViewModel cập nhật UiState chính xác. Kiểm thử tích hợp xác minh PermissionHandler thực với ActivityScenario, nhưng thường chỉ có 2-3 kiểm thử như vậy cho mỗi ứng dụng — các kịch bản còn lại được bao phủ bởi kiểm thử đơn vị với fakes.

Các mẫu phổ biến và lỗi thường gặp

Các lỗi điển hình khi làm việc với Permission Handler bao gồm: không kiểm tra checkSelfPermission trước mỗi lời gọi API, bỏ qua shouldShowRequestPermissionRationale, gọi lại requestPermissions sau Never Ask Again và lưu trữ trình khởi chạy mà không xét đến vòng đời Activity. Hãy xem xét từng vấn đề và giải pháp.

Lỗi phổ biến nhất là gọi API mà không kiểm tra trạng thái quyền. Các nhà phát triển cho rằng nếu quyền đã được cấp một lần, nó sẽ tồn tại mãi mãi. Tuy nhiên, người dùng có thể thu hồi nó qua cài đặt bất cứ lúc nào. Một Permission Handler phải luôn gọi isPermissionGranted trước khi thực hiện thao tác nhạy cảm. Lỗi phổ biến thứ hai là bỏ qua shouldShowRequestPermissionRationale và lặp lại yêu cầu, dẫn đến từ chối ngay lập tức mà không có hộp thoại trong chế độ Never Ask Again.

Các thực hành tốt nhất bao gồm: tạo một phiên bản Handler duy nhất cho toàn bộ vòng đời Activity, sử dụng SharedFlow để truyền kết quả đến ViewModel, ghi nhật ký tất cả yêu cầu và từ chối để phân tích, và hiển thị hộp thoại giải thích tùy chỉnh trước hộp thoại hệ thống khi từ chối lần đầu. Tuân theo các quy tắc này đảm bảo xử lý quyền ổn định trên tất cả các phiên bản Android.

Câu hỏi thường gặp

Permission Handler trong Android là gì?

Permission Handler là một thành phần để quản lý tập trung các quyền runtime, đóng gói checkSelfPermission, requestPermissions và shouldShowRequestPermissionRationale. Nó đơn giản hóa bảo trì mã và cải thiện kiểm thử.

Nên sử dụng API nào cho Handler trong 2024?

Khuyến nghị sử dụng ActivityResultContracts.RequestPermission từ thư viện androidx.activity. Nó thay thế onRequestPermissionsResult cũ và cung cấp API callback sạch với kết quả Boolean.

Có cần Handler cho một quyền không?

Cho một quyền, Handler không bắt buộc — bạn có thể sử dụng lời gọi trực tiếp đến trình khởi chạy RequestPermission trong Activity. Handler trở nên cần thiết với 3 quyền trở lên để tránh trùng lặp mã.

Làm thế nào để kiểm thử Permission Handler?

Tạo một giao diện PermissionHandler và triển khai giả của nó cho kiểm thử đơn vị. Bản giả trả về kết quả định trước mà không cần gọi hệ thống. Điều này cho phép kiểm thử ViewModel và logic UI mà không cần trình giả lập.

Làm thế nào để xử lý Never Ask Again trong Handler?

Sau khi từ chối, kiểm tra shouldShowRequestPermissionRationale. Nếu phương thức trả về false — chế độ Never Ask Again đang hoạt động. Handler nên trả về PermissionResult.DENIED(false) và UI nên hiển thị nút để chuyển đến Cài đặt.

Tóm tắt

  • Permission Handler là một thành phần kiến trúc để quản lý tập trung các quyền runtime Android.
  • Dựa trên ActivityResultContracts.RequestPermission từ thư viện androidx.activity.
  • Một giao diện với các phương thức cho mỗi quyền đơn giản hóa kiểm thử đơn vị qua các triển khai giả.
  • Tích hợp với ViewModel qua StateFlow tách mã nền tảng khỏi logic kinh doanh.
  • Lỗi điển hình: thiếu checkSelfPermission, bỏ qua giải thích và Never Ask Again.
  • Thực hành tốt nhất — một Handler cho mỗi Activity được đăng ký trong onCreate.
  • Tập trung hóa giảm số lượng lỗi Permission Denial 60 phần trăm trong các dự án điển hình.

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm