rsktash
01/27/2022, 9:29 PMunregister
is not being called when navigated back from inner router
The error occurs when
1. I navigate to inner router component A.
2. Navigate back
3. and again navigate to router component A
Root Router -> Inner Router -> Child -> NavBack -> Navigate forwardArkadii Ivanov
01/27/2022, 10:10 PMtrashcoder
03/10/2022, 10:04 PMdecompose
0.3.1 to a newer version (i tried with 0.5.1, 0.5.0 and 0.4.0). the code does compile (i only had to update the imports for the router
package) but i do get an error during runtime.
what i do:i have 3
Configurations
with 3 Childs
. some Childs
use the same components, so i thought it would be nice, if the components would only be created once, so that their state is shared between `Configurations`/`Childs`.
how i implemented it (works withso instead of creating a component in the0.3.1):decompose
createChild()
function (which is provided as childFactory
) and using its ComponentContext
, i created variables in the root component (like the one for the routerState
) and used the ComponentContext.childContext()
function.
class RootComponent internal constructor(
componentContext: ComponentContext,
private val hue: (ComponentContext, (Hue.Output) -> Unit) -> Hue,
private val homematicIP: (ComponentContext, (HomematicIP.Output) -> Unit) -> HomematicIP
) : Root, ComponentContext by componentContext {
constructor(
...
)
override val hueComponent: Hue
// the following line fails
get() = hue(childContext("hueComponent"), this::onHueOutput)
override val homematicIPComponent: HomematicIP
get() = homematicIP(childContext("homematicIPComponent"), this::onHomematicIPOutput)
private val router =
router<Configuration, Root.Child>(
initialConfiguration = Configuration.Dashboard,
handleBackButton = true,
childFactory = ::createChild
)
override val routerState: Value<RouterState<*, Root.Child>> = router.state
private fun createChild(configuration: Configuration, componentContext: ComponentContext): Root.Child =
when (configuration) {
is Configuration.Dashboard -> Root.Child.Dashboard(hueComponent, homematicIPComponent)
is Configuration.Hue -> Root.Child.Hue(hueComponent)
is Configuration.HomematicIP -> Root.Child.HomematicIP(homematicIPComponent)
}
...
}
interface Root {
val hueComponent: Hue
val homematicIPComponent: HomematicIP
val routerState: Value<RouterState<*, Child>>
sealed class Child {
data class Dashboard(
val hueComponent: com.trashcoder.trashboard.common.philips_hue.integration.Hue,
val homematicIPComponent: com.trashcoder.trashboard.common.homematic_ip.integration.HomematicIP) : Child()
data class Hue(
val hueComponent: com.trashcoder.trashboard.common.philips_hue.integration.Hue) : Child()
data class HomematicIP(
val homematicIPComponent: com.trashcoder.trashboard.common.homematic_ip.integration.HomematicIP) : Child()
}
...
}
Exception in thread "main" java.lang.IllegalStateException: Check failed.
at com.arkivanov.essenty.statekeeper.DefaultStateKeeperDispatcher.register(DefaultStateKeeperDispatcher.kt:42)
at com.arkivanov.decompose.statekeeper.ChildStateKeeperKt.child(ChildStateKeeper.kt:11)
at com.arkivanov.decompose.ComponentContextExtKt.childContext(ComponentContextExt.kt:21)
at com.arkivanov.decompose.ComponentContextExtKt.childContext$default(ComponentContextExt.kt:18)
at com.trashcoder.trashboard.common.root.integration.RootComponent.getHueComponent(RootComponent.kt:50)
Arkadii Ivanov
03/10/2022, 10:34 PMhueComponent
getter calls childContext("hueComponent")
every time when it is called. The second attempt of creating child context with the same key will fail. One of the possible fixes is to use lazy
instead:
override val hueComponent: Hue by lazy { hue(childContext("hueComponent"), this::onHueOutput) }
Or maybe you can just assign the value (depends on your needs)
override val hueComponent: Hue = hue(childContext("hueComponent"), this::onHueOutput)
trashcoder
03/10/2022, 10:59 PMpush
and replaceCurrent
) to bringToFront
to ensure unique Configurations
...
Thanks again! :kotlin-intensifies: