CODAR747
CODAR747

Reputation: 174

How to handle unnecessary recompositions within if-else statement in jetpack compose?

I'm using if-else state in jetpck compose project to compose UI. It working fine as it needed but the problem is that even if the first if statements are to be passed it shouls a flicker effect of that ui as well and then show the final ui that is supposed to be shown. For example we have AccessInfo() and MediaScreen() now in if statement these are to be composed in sequence wihtout any flickering or recompositon.

Here what i have tried

@Composable
fun PermissionHandler(
    viewModel: HomeViewModel,
    state: HomeUIState
) {

    val context = LocalContext.current
    val permissionsState = rememberMultiplePermissionsState(permissions)
    var selectedUri: Uri?
    val safLauncher =
        rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            if (result.resultCode == RESULT_OK) {
                selectedUri = result.data?.data
                if (selectedUri != null) {
                    if (selectedUri.toString() == "content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fmedia") {
                        viewModel.saveSAFValue(true)
                        context.contentResolver.takePersistableUriPermission(
                            selectedUri!!,
                            Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
                        )
                    }
                }
            }
        }


    if (!permissionsState.allPermissionsGranted) {
        AccessInfo(
            accessModel = AccessModel(
                lottieComposition = R.raw.gallery_permission,
                title = R.string.permission_required,
                description = R.string.permission_read_and_write,
                buttonText = R.string.allow_access_button
            ),
            onAllowButtonClick = { permissionsState.launchMultiplePermissionRequest() })
    } else if (!state.isSAFGranted) {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
            .apply {
                addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION)
                addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
            }
        AccessInfo(
            accessModel = AccessModel(
                lottieComposition = R.raw.gallery_permission,
                title = R.string.folder_access_required,
                description = R.string.folder_access_required_desc,
                buttonText = R.string.allow_folder_access_button,
                linkText = R.string.why_we_need_this,
                popUpContent = R.array.SAF_requirement_details,
                popUpButtonText = R.string.allow_folder_access_button
            ),
            isPopupEnabled = true,
            onAllowButtonClick = { safLauncher.launch(intent) })
    } else {
        MediaScreen()
    }
}

Upvotes: 1

Views: 147

Answers (1)

Phil Dukhov
Phil Dukhov

Reputation: 88072

Compose has movableContentOf for such use-case. If it's called once in different locations, same view will be reused - just make sure you're handling parameters change in AccessInfo correctly.

val accessInfo = movableContentOf { isPopupEnabled: Boolean, onAllowButtonClick: () -> Unit ->
    AccessInfo(
        accessModel = /*...*/,
        isPopupEnabled = isPopupEnabled,
        onAllowButtonClick = onAllowButtonClick
    )
}

if (!permissionsState.allPermissionsGranted) {
    accessInfo(
        false,
        { permissionsState.launchMultiplePermissionRequest() }
    )
} else if (!state.isSAFGranted) {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
        .apply {
            addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION)
            addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
        }
    accessInfo(
        true,
        { safLauncher.launch(intent) }
    )
}

Upvotes: 0

Related Questions