Search code examples
androidkotlinandroid-jetpack-composeandroid-jetpackside-effects

How to start new activity in jetpack compose


I want to start new activity in jetpack compose. So I want to know what is the idiomatic way of doing in jetpack compose. Is any side effect api need to be use or not when opening.

ClickableItemContainer.kt

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun ClickableItemContainer(
    rippleColor: Color = TealLight,
    content: @Composable (MutableInteractionSource) -> Unit,
    clickAction: () -> Unit
) {
    val interactionSource = remember { MutableInteractionSource() }
    CompositionLocalProvider(
        LocalRippleTheme provides RippleTheme(rippleColor),
        content = {
            Surface(
                onClick = { clickAction() },
                interactionSource = interactionSource,
                indication = rememberRipple(true),
                color = White
            ) {
                content(interactionSource)
            }
        }
    )
}

MaterialButton.kt

@Composable
fun MaterialButton(
    text: String,
    spacerHeight: Dp,
    onActionClick: () -> Unit
) {
    Spacer(modifier = Modifier.height(spacerHeight))
    ClickableItemContainer(rippleColor = AquaDarker, content = {
        Box(
            modifier = Modifier
                      .background(Aqua)
                      .fillMaxWidth(),
        ) {
            Text(
                text = text,
                modifier = Modifier
                    .align(Alignment.Center),
                style = WhiteTypography.h5
            )
        }
    }) {
        onActionClick()
    }
}

OpenPermissionSetting.kt

@Composable
fun OpenPermissionSetting(router: Router = get()) {
    val activity = LocalContext.current as Activity
    MaterialButton(
        text = "Open Setting",
        spacerHeight = 10.dp
    ) {
      activity.startActivity(Intent(this@CurrentClassName,RequiredClassName::class.java)
    }
}

So my question is this intent should be use in any Side-effect i.e. LaunchEffect?

LaunchedEffect(key1 = true){
        activity.startActivity(Intent(this@CurrentClassName,RequiredClassName::class.java)
    }

Thanks


Solution

  • @Composable
    fun OpenPermissionSetting(router: Router = get()) {
        val activity = LocalContext.current as Activity
        MaterialButton(
            text = "Open Setting",
            spacerHeight = 10.dp
        ) {
          activity.startActivity(Intent(this@CurrentClassName,RequiredClassName::class.java)
        }
    }
    

    And this one opens new Activity when Button is clicked

    var startNewActivity by remember {mutabelStateOf(false)}
    @Composable
    fun OpenPermissionSetting(router: Router = get()) {
        MaterialButton(
            text = "Open Setting",
            spacerHeight = 10.dp
        ) {
            startActivity = true
        }
    }
    
    
    LaunchedEffect(key1 = startActivity){
        if(startActivity) {
                  activity.startActivity(Intent(this@CurrentClassName,RequiredClassName::class.java)
        }
    }
    

    This one opens activity as soon as your Composable enters composition .Setting a true, false, Unit key or any key doesn't change the fact that code inside LaunchedEffect will be invoked in when it enters composition. You can however change when that code will be run again using key or keys and a conditional statement inside LaunchedEffect.

    LaunchedEffect(key1 = true){
            activity.startActivity(Intent(this@CurrentClassName,RequiredClassName::class.java)
        }
    

    You should understand use cases SideEffect api how they work and ask yourself if this applies to my situation.

    SideEffect is good for situations when you only want an action to happen if composition happens successfully. If, even if small chance your state changes fast and current composition is ignored then you shouldn't invoke that action for instance logging composition count is a very good use case for SideEffect function.

    Recomposition starts whenever Compose thinks that the parameters of a composable might have changed. Recomposition is optimistic, which means Compose expects to finish recomposition before the parameters change again. If a parameter does change before recomposition finishes, Compose might cancel the recomposition and restart it with the new parameter.

    When recomposition is canceled, Compose discards the UI tree from the recomposition. If you have any side-effects that depend on the UI being displayed, the side-effect will be applied even if composition is canceled. This can lead to inconsistent app state.

    Ensure that all composable functions and lambdas are idempotent and side-effect free to handle optimistic recomposition.

    LaunchedEffect is good for when you wish to have a coroutineScope for animations, scrolling or calling other suspending functions. Another use case for LaunchedEffect is triggering one time actions when the key or keys you set changes.

    As in sample above if you set key for LaunchedEffect and check if it's true in a code block you can trigger action only condition is true. LaunchedEffect is also useful when actions that don't require user interactions but a state change happens and only needs to be triggered once.

    Executing a callback only when reaching a certain state without user interactions

    DisposableEffect is required when you wish to check when your Composable enters and exits composition. onDispose function is also useful for clearing resources or callbacks, sensor register, or anything that needs to be cleared when your Composable exits recomposition.