Decomposable loads view multiple times

51 Views Asked by At

I am new to Kotlin multiplatform projects and am currently working on implementing a navigation controller using Decomposable architecture (android & iOS). The following process I have structured is based on the documentation, but unfortunately found a key limitation. That is, when a new component is pushed/bringToFont in navigation stack, it calls all previous components of child stack multiple times, and and then navigates the desired component at last. This inefficiency significantly impacts UI navigation speed. I am seeking a solution to properly structure navigation in multiplatform project.

class Screen_1_Component(
    componentContext: ComponentContext,
    val onClickGo: ()->Unit,
) {}
class Screen1View(val component: Screen_1_Component) {
    @Composable fun loadView(){
        Button(content = { Text("Go To Screen 2") }, onClick = { component.onClickGo() })
    }
}

class Screen_2_Component(
    componentContext: ComponentContext,
    val onClickBack: ()->Unit,
) {}

class Screen2View(val component: Screen_2_Component) {
    @Composable fun loadView(){
        Button(content = { Text("Back To Screen 1") }, onClick = { component.onClickBack() })
    }
}

class Root_Component(componentContext: ComponentContext): ComponentContext by componentContext {
    private val navigation = StackNavigation<_Configuration>()
    val childStack = childStack(
        source = navigation,
        serializer = _Configuration.serializer(),
        initialConfiguration = _Configuration.Screen1,
        handleBackButton = true,
        childFactory = ::createChild
    )
    @OptIn(ExperimentalDecomposeApi::class)
    private fun createChild(config: _Configuration, context: ComponentContext): _Child {
        return when(config) {
            is _Configuration.Screen1 -> _Child.Screen1(
                Screen_1_Component(context, onClickGo = {
                    navigation.bringToFront(_Configuration.Screen2)
                })
            )
            is _Configuration.Screen2 -> _Child.Screen2(
                Screen_2_Component(context, onClickBack = {
                    navigation.pop()
                })
            )
        }
    }

    sealed class _Child {
        data class Screen1(val component: Screen_1_Component): _Child()
        data class Screen2(val component: Screen_2_Component): _Child()
    }

    @Serializable sealed class _Configuration {
        @Serializable data object Screen1: _Configuration()
        @Serializable data object Screen2: _Configuration()
    }

    @Composable fun showView() {
        val childStack by childStack.subscribeAsState()
        Children(
            stack = childStack,
            animation = stackAnimation(slide())
        ) { child ->
            when(val instance = child.instance) {
                is Root_Component._Child.Screen1 -> {
                    Screen1View(instance.component).loadView()
                }
                is Root_Component._Child.Screen2 -> {
                    Screen2View(instance.component).loadView()
                }
            }
        }
    }
}
0

There are 0 best solutions below