以下代码来自Android开发者文档。它解释了如何请求权限。
// Register the permissions callback, which handles the user's response to the // system permissions dialog. Save the return value, an instance of // ActivityResultLauncher. You can use either a val, as shown in this snippet, // or a lateinit var in your onAttach() or onCreate() method. val requestPermissionLauncher = registerForActivityResult(RequestPermission() ) { isGranted: Boolean -> if (isGranted) { // Permission is granted. Continue the action or workflow in your // app. } else { // Explain to the user that the feature is unavailable because the // features requires a permission that the user has denied. At the // same time, respect the user's decision. Don't link to system // settings in an effort to convince the user to change their // decision. } }
我尝试在我的应用程序中使用该代码。当
isGranted
为 true 时,我尝试渲染我的主用户界面。但它不起作用,因为我收到以下错误:
@Composable 调用只能在 @Composable 函数的上下文中发生
我想知道为什么会发生这种情况,因为我从可组合上下文中调用启动器。是否有必要将调用堆栈中的每个函数都标记为
@Composable
?如果是这样,如何使闭包传递给 registerForActivityResult
可组合?
您应该定义一个在结果返回后更新的状态。 记住的状态可以在有状态可组合项中或作为参数出现。 更新记住的状态将触发重组。
registerForActivity
中传入的Lambda是回调,在重组时会多次传递,但只会回调最后一次传递的。
你可以这样做:
@Composable
fun OnPermissionGranted(permission : String, launch : Boolean, onGranted : @Composable () -> Unit ){
val context = LocalContext.current
var granted by remember { mutableStateOf(checkIfGranted(context) ) }
val launcher = rememberLauncherForActivityResult(contract = ActivityResultContracts.RequestPermission()){
if(it){
granted = true
}
}
LaunchedEffect(granted, launch){
if(!granted && launch){
launcher.launch(permission)
}
}
if(granted){
onGranted()
}
}
它似乎以某种方式起作用。
package com.example.konretsca
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.app.ActivityCompat
import com.example.konretsca.ui.theme.KonretscaTheme
fun debug (msg: String) {
Log.d ("konretsca", msg)
}
class MainActivity : ComponentActivity() {
override fun onCreate (savedInstanceState: Bundle?) {
super.onCreate (savedInstanceState)
debug ("onCreate")
setContent {
val permission =
ActivityCompat.checkSelfPermission (
LocalContext.current,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED
var granted by remember { mutableStateOf (permission) }
val launcher = rememberLauncherForActivityResult (ActivityResultContracts.RequestPermission()) {
granted = it
}
if(!granted){
SideEffect {
launcher.launch(Manifest.permission.CAMERA)
}
}
else {
KonretscaTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Main()
}
}
}
}
}
}
@Composable
fun Main () {
Text (text = "Main")
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview () {
KonretscaTheme {
Main ()
}
}