Home > Net >  How to start new activity in jetpack compose
How to start new activity in jetpack compose

Time:09-28

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

CodePudding user response:

Composables are designed to only propagate states down the hierarchy, and propagate actions up the hierarchy. So, no, you shouldn't be launching activities from within the composable. You need to trigger a callback, like your onActionClick: () -> Unit, to the original ComponentActivity where your composables reside (and if this has to go through several nested composables, you'll need to propagste that action all the way up). Then, in your activity, you can direct it to process the actions that were selected. Something like this:

in ComponentActivity:

ClickableItemContainer(
    rippleColor = ...,
    content = ...,
    clickAction = {
        startActivity(...)
    }
)

CodePudding user response:

@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.

CodePudding user response:

I would use just LaunchedEffect with the flag let's say val showActivity: Boolean, and the LaunchedEffect function would look like:

@Composable
fun OpenPermissionSetting(viewModel: ViewModel) {
    val uiState = viewModel.uiState
    MaterialButton(
        text = "Open Setting",
        spacerHeight = 10.dp
    ) {
        viewModel.onShowActivity()
    }
}


LaunchedEffect(showActivity){
    if (uiState.showActivity) {
        activity.startActivity(...)
        viewModel.onShowActivityDone()
    }
}

Remember to avoid leaving the flag on true, because its may cause some problems if you have more recompositions :)

  • Related