|
|
我想找到 super.onRequestPermissionsResult(requestCode, permissions, grantResults) 这个方法 的替代方法,可以避免使用已经废弃的该方法,也就避免了@Deprecated("Deprecated in Java") 这个声明,请详解
已完成分析,参考了10篇资料
替代 onRequestPermissionsResult 的现代方案:Activity Result API
从 AndroidX Activity 1.2.0 和 Fragment 1.3.0 开始,Google 官方推荐使用 Activity Result API 来替代已废弃的 onRequestPermissionsResult 回调方式。下面详细讲解替代方案。
为什么被废弃
传统的 onRequestPermissionsResult 存在以下问题:
需要手动管理 requestCode,容易出错
回调分散,代码可读性差
与 Activity/Fragment 的生命周期耦合紧密
多个权限请求时代码臃肿
新的 Activity Result API 提供了类型安全、生命周期感知、模块化的解决方案。
核心替代方案:registerForActivityResult()
添加依赖
gradle
编辑
implementation "androidx.activity:activity-ktx:1.8.0"
implementation "androidx.fragment:fragment-ktx:1.6.0"
单个权限请求
kotlin
编辑
class MainActivity : AppCompatActivity() {
// 在类成员位置注册(必须在 onCreate 之前执行)
private val cameraPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
// 这里是回调,直接拿到结果
if (isGranted) {
// 权限已授予
openCamera()
} else {
// 权限被拒绝
showPermissionDeniedDialog()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
private fun checkCameraPermission() {
when {
// 已拥有权限
ContextCompat.checkSelfPermission(
this, Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
openCamera()
}
// 需要显示解释说明(用户之前拒绝过但未勾选"不再询问")
shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> {
showRationaleDialog {
cameraPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
// 直接请求权限
else -> {
cameraPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
}
}
多个权限批量请求
kotlin
编辑
private val multiPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions: Map<String, Boolean> ->
// permissions 是一个 Map,key 是权限名,value 是是否授予
val allGranted = permissions.values.all { it }
if (allGranted) {
startFeature()
} else {
val denied = permissions.filter { !it.value }.keys
Snackbar.make(binding.root, "被拒绝: $denied", Snackbar.LENGTH_LONG)
.setAction("去设置") { openAppSettings() }
.show()
}
}
private fun requestPermissions() {
multiPermissionLauncher.launch(
arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.ACCESS_FINE_LOCATION
)
)
}
新旧方式对比
表格
对比项 旧方式onRequestPermissionsResult 新方式registerForActivityResult
请求码管理 手动定义 requestCode 常量 无需管理,系统自动处理
结果处理 在统一回调中通过 switch/case 分发 每个 launcher 有独立回调
类型安全 String[] 和 int[],易出错 Boolean 或 Map<String, Boolean>
生命周期 容易在配置变更后丢失状态 生命周期感知,自动处理
代码位置 分散在回调中 与请求逻辑紧密相邻
处理"不再询问"场景
当用户勾选"不再询问"并拒绝后,shouldShowRequestPermissionRationale() 返回 false,此时需要引导用户手动前往设置页:
kotlin
编辑
private fun openAppSettings() {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.parse("package packageName")
}
startActivity(intent)
}
封装为可复用的工具类
如果多个页面都需要权限请求,可以封装一个工具类:
kotlin
编辑
class PermissionHelper(private val activity: FragmentActivity) {
private val launcher = activity.registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { grantResults ->
handleResult(grantResults)
}
private var onAllGranted: (() -> Unit)? = null
private val permissionsMap = mapOf(
Manifest.permission.CAMERA to "摄像头",
Manifest.permission.READ_EXTERNAL_STORAGE to "存储",
)
fun requestPermissions(onAllGranted: () -> Unit) {
this.onAllGranted = onAllGranted
val permissions = permissionsMap.keys.toTypedArray()
launcher.launch(permissions)
}
private fun handleResult(results: Map<String, Boolean>) {
val denied = results.filter { !it.value }.keys
if (denied.isEmpty()) {
onAllGranted?.invoke()
} else {
// 处理被拒绝的权限
showPermissionDeniedDialog(denied)
}
}
}
关键注意事项
注册时机:registerForActivityResult() 必须在 onCreate() 中或之前调用,不能在按钮点击等懒加载场景中创建,否则会抛出 IllegalStateException
生命周期安全:launcher 会自动感知生命周期,在 Activity/Fragment 销毁时自动清理
配置变更:屏幕旋转等配置变更后,回调仍然能正确触发
Fragment 中同样适用:在 Fragment 中使用方式完全一致
总结
用 registerForActivityResult(ActivityResultContracts.RequestPermission()) 或 RequestMultiplePermissions() 替代旧的 requestPermissions() + onRequestPermissionsResult() 组合,可以获得更简洁、类型安全、生命周期感知的权限请求体验。不再需要 super.onRequestPermissionsResult(),也彻底告别了 @Deprecated 警告。 |
|