The following code is from the Android Developer Docs. It explains how to request permissions.
// 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. } }
I tried to use the code in my application. When isGranted
is true I tried render my main ui. But it does not work, because I get the following error:
@Composable invocations can only happen from the context of a @Composable function
I am wondering why this happens, because I call the launcher from a composable context. Is it necessary to mark every function in the call stack as @Composable
? And if so, how to make the closure passed to registerForActivityResult
composable?
You should define a state that is updated once the result is returned. That remembered state can within your statefull composable or coming as parameter. Updating the remembered state will trigger recomposition.
Lambda passed in the registerForActivity
is callback and it is passed multiple times in recomposition but only the last one that has been passed is called back.
You can do something like this:
@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()
}
}