Permission called twice when we have mutableStateOf in Jetpack compose

Ali

I have following permission check in Jetpack Compose :

val launcher = rememberLauncherForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
    if (permissions.values.first { true }) {
        log.info("Permission is granted")
        shouldDisplayQuestionDialog.value = true
    } else {
        log.info("Permission is not granted")
    }
}

When I deny permission, Permission is not granted log called once.

Now I change the code to this :

val displayEmptyScreen = remember { mutableStateOf(false) }
val launcher = rememberLauncherForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
    if (permissions.values.first { true }) {
        log.info("Permission is granted")
        shouldDisplayQuestionDialog.value = true
    } else {
        log.info("Permission is not granted")
        displayEmptyScreen.value = true
    }
}

Now Permission is not granted log called twice after adding the mutableStateOf. Why is that? How to make it call once?

ADDENDA

@Composable
    private fun DisplayPermissionDialog(shouldDisplayQuestionDialog: MutableState<Boolean>) {
        val displayEmptyScreen = remember { mutableStateOf(false) }
        val launcher = rememberLauncherForActivityResult(
            ActivityResultContracts.RequestMultiplePermissions()
        ) { permissions ->
            if (permissions.values.first { true }) {
                log.info("Permission is granted")
                shouldDisplayQuestionDialog.value = true
            } else {
                log.info("Permission is not granted")
                displayEmptyScreen.value = true
            }
        }
        DisplayQuestionAlertDialog(shouldDisplayQuestionDialog)
        if (displayEmptyScreen.value) {
            Box {
                // This box works as background
                Box(
                    modifier = Modifier
                        .matchParentSize()
                        .background(Color.White)
                )
            }
        }
        val context = LocalContext.current
        when (PackageManager.PERMISSION_GRANTED) {
            ContextCompat.checkSelfPermission(
                context,
                Manifest.permission.READ_EXTERNAL_STORAGE
            ) -> {
                LaunchedEffect(Unit) {
                    log.info("Set State for mutableStateFlow")
                    viewModel.setState()
                }
                DisplayQuestionAlertDialog(shouldDisplayQuestionDialog)
            }
            else -> {
                Handler(Looper.getMainLooper()).post {
                    // Asking for permission
                    launcher.launch(
                        arrayOf(
                            Manifest.permission.READ_EXTERNAL_STORAGE,
                            Manifest.permission.WRITE_EXTERNAL_STORAGE
                        )
                    )
                }
            }
        }
    }
CommonsWare

Your code guarantees that DisplayPermissionDialog() will be called at least twice, if you do not hold the permission at the time that you called DisplayPermissionDialog() initially.

The first time through, if you do not hold permission, you will go into the else branch of your when(), and you will use your launcher to bring up a system permission dialog. That will eventually trigger your lambda on launcher, which mutates state whether you were granted permission or not.

Since DisplayPermissionDialog() reads that same state, DisplayPermissionDialog() will be called a second time (the function is "recomposed"). And, on that second time through if you do not hold permission, you will go into the else branch of your when(), and you will use your launcher to bring up a system permission dialog. That will eventually trigger your lambda on launcher, which mutates state whether you were granted permission or not.

Frankly, I would expect an infinite chain of recompositions once you get to the point where Android stops showing the system permission dialog.

Either:

  • Do not mutate state that this function reads when the user rejects your permission request, or

  • Arrange it such that you do not call launch() on your launcher on every call of this function when you do not hold permission

I cannot give you more specific advice, just because this is not my function and I do not fully understand what you're trying to do here.

For more, you might want to watch this screencast on runtime permissions in Compose UI. Or, try Accompanist's permission composables — see this Medium post for more on that library.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

MutableStateOf is not being re-initialized in Jetpack Compose

Jetpack Compose: mutableStateOf doesn't update with flow

Jetpack compose mutablestateof list doesn't trigger recompose when changing property value in list item class

mutableStateOf holding the value after the recomposition without remember API in Jetpack Compose

Android Jetpack Compose rememberSystemUiController() doesn't observe mutableStateOf()

Jetpack compose mutableStateOf list doesn't trigger re-composition when changing property value in list item class

Jetpack Compose LargeTopAppBar Displays Title Twice

Runtime Bluetooth permission not showing in jetpack compose

Jetpack Compose animation finished listener not called

Navigation is being called every time in Jetpack Compose

When the move constructor is actually called if we have (N)RVO?

When to use derivedStateOf in Jetpack Compose?

Why can't I get the same instance of class when I have used remember in Android Jetpack Compose?

How to have a layout like this in Jetpack Compose

Hibernate 4.3, when building SessionFactory why do we have to supply the properties twice?

How we can use intent for row items in android jetpack compose?

How we can use bottom sheet in jetpack compose?

How we can use toggle button for per row in jetpack compose?

how can we create a circular checkbox in jetpack compose?

Jetpack Compose ExposedDropdownMenu not showing up when pressed

Keyboard flickering when programmatically hidden in Jetpack Compose

Composable not recomposing when list is cleared in jetpack compose

Remember not recompose when value change in jetpack compose

Getting error when running Jetpack Compose samples

Change the size of ModalDrawer when expanded, Jetpack Compose

How to clear backstack when browsing Jetpack Compose?

Remember mutableStateOf custom class in Android Compose

None of the following functions can be called with the arguments supplied on koin in jetpack compose

LaunchedEffect not called on Box while UI testing in Jetpack Compose