Kotlin/Compose:如何在Activity外部获取权限请求的结果?
兄弟,你说的这个痛点我太熟悉了!自从升级到androidx.activity:1.10.0后,CompositionLocalProvider确实能让我们在Compose树的任何地方拿到LocalActivity.current,直接调用activity.requestPermissions发起权限请求完全没问题,但结果根本拿不到——这就尴尬了对吧?毕竟registerForActivityResult只能在Activity里用,总不能把权限请求的逻辑都塞回Activity里吧?
别慌,Compose专门给我们准备了解决方案:rememberLauncherForActivityResult!这个API是专门适配Compose场景的,它可以在任何Composable函数里使用,哪怕你的Composable是嵌套在N层子组件里(也就是你说的“Activity外部”),都能正常拿到权限请求的结果。
单个权限请求的示例
先看最简单的单个权限请求,比如相机权限:
@Composable fun PermissionRequestButton() { // 记住权限请求Launcher,和Composable生命周期绑定 val permissionLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.RequestPermission() ) { isGranted: Boolean -> // 这里就是权限请求的结果回调,直接处理就行! if (isGranted) { // 权限通过,该干嘛干嘛 Toast.makeText(LocalContext.current, "相机权限已授予", Toast.LENGTH_SHORT).show() } else { // 权限被拒绝,要么提示用户,要么引导去设置页 Toast.makeText(LocalContext.current, "相机权限被拒绝,无法使用相机功能", Toast.LENGTH_SHORT).show() } } // 触发请求的按钮 Button(onClick = { permissionLauncher.launch(Manifest.permission.CAMERA) }) { Text("请求相机权限") } }
你看,这个PermissionRequestButton可以放在任何Compose层级里,哪怕它是某个自定义的子组件,只要在Compose树中,就能正常触发请求并获取结果,完全不需要依赖Activity的直接代码。
多个权限请求的情况
如果需要一次性请求多个权限,比如相机+存储,就用ActivityResultContracts.RequestMultiplePermissions():
@Composable fun MultiplePermissionRequestButton() { val context = LocalContext.current val multiplePermissionLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.RequestMultiplePermissions() ) { permissionsMap -> // 遍历每个权限的结果 permissionsMap.forEach { (permission, isGranted) -> when (permission) { Manifest.permission.CAMERA -> { val message = if (isGranted) "相机权限已授予" else "相机权限被拒绝" Toast.makeText(context, message, Toast.LENGTH_SHORT).show() } Manifest.permission.READ_EXTERNAL_STORAGE -> { val message = if (isGranted) "存储权限已授予" else "存储权限被拒绝" Toast.makeText(context, message, Toast.LENGTH_SHORT).show() } } } } Button(onClick = { // 传入要请求的权限数组 multiplePermissionLauncher.launch( arrayOf( Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE ) ) }) { Text("请求相机和存储权限") } }
为什么这个方法可行?
rememberLauncherForActivityResult内部已经帮我们处理了和Activity的生命周期绑定,以及结果回调的注册逻辑,不需要我们手动去调用registerForActivityResult,完美避开了“只能在Activity里注册”的限制。而且它会随着Composable的销毁自动解绑,不会有内存泄漏的问题,比直接用Activity的requestPermissions靠谱多了。
备注:内容来源于stack exchange,提问作者Exicode

