I have this small piece of code: ``` setCo...
# compose
b
I have this small piece of code:
Copy code
setContent {
            AppState.currentScreen = Screen.LoadingScreen

            Log.d(TAG, "set content")
            MaterialTheme(colors = darkColorPalette()) {
                Log.d(TAG, "Material Theme")
                Providers(MainActivityAmbient provides this, DiAmbient provides di) {
                    Log.d(TAG, "Providers")
                    Crossfade(AppState.currentScreen) {
                        Log.d(TAG, "Crossfade $AppState")
                        Log.d(TAG, "Crossfade ${AppState.currentScreen}")
but the crossfade is called twice If I try to change the currentScreen in the crossfade, I end up in a loop that never ends. How is one supposed to use Crossfade?
Here is an example of how I am currently changing the screen:
Copy code
when (it) {
                            is Screen.LoadingScreen -> {
                                //todo Load stuff I guess
                                Log.d(TAG, "State Loading")
                                launchInComposition {
                                    delay(1000)
                                    AppState.currentScreen = Screen.PostScreen("all")
                                }
                            }
a
there is a param in the Crossfade trailing lambda which you should use instead of "AppState.currentScreen". when you switch from the previous screen to the new one Crossfade creates two instances of the trailing lambda during the animation, one for displaying the old screen and one for the current one
Copy code
Crossfade(AppState.currentScreen) { screen -> 
   Log.d(TAG, "Crossfade $screen")
}
b
Hmm, even changing it to use the trailing parameter and the crossfade is called twice still:
Copy code
2020-06-18 09:25:41.897 30605-30605/com.bohregard.stack D/MainActivity: set content
2020-06-18 09:25:41.938 30605-30605/com.bohregard.stack D/MainActivity: Material Theme
2020-06-18 09:25:41.941 30605-30605/com.bohregard.stack D/MainActivity: Providers
2020-06-18 09:25:41.992 30605-30605/com.bohregard.stack D/MainActivity: Crossfade com.bohregard.stack.model.enums.Screen$LoadingScreen@fc2cb1a
2020-06-18 09:25:41.993 30605-30605/com.bohregard.stack D/MainActivity: State Loading
2020-06-18 09:25:42.554 30605-30605/com.bohregard.stack D/MainActivity: Crossfade com.bohregard.stack.model.enums.Screen$LoadingScreen@fc2cb1a
2020-06-18 09:25:42.554 30605-30605/com.bohregard.stack D/MainActivity: State Loading
Copy code
setContent {
            AppState.currentScreen = Screen.LoadingScreen

            Log.d(TAG, "set content")
            MaterialTheme(colors = darkColorPalette()) {
                Log.d(TAG, "Material Theme")
                Providers(MainActivityAmbient provides this, DiAmbient provides di) {
                    Log.d(TAG, "Providers")
                    Crossfade(AppState.currentScreen) { screen ->
                        Log.d(TAG, "Crossfade $screen")
It did fix my death loop that never ended though 🙂
a
You also don't want to initialize currentScreen inside the setContent block; if compose decides to recompose that scope for whatever reason, you'll reset back to the loading screen
👍 1
b
Yeah, I removed that from the setContent screen. I forgot I stuck that there as I was grasping for straws to figure out why it kept looping over and over 🙃
👍 1
a
there is nothing wrong of composable executed twice sometimes. this is an idea of composable functions that they are reexecuted when the framework requires it to, or repocomposition can be smartly skipped, and your code should not assume that the function will be called some exact amount of times. maybe there is some optimization possible in Crossfade implementation thought. could you please describe why is it important for you in this case?
b
I think for me I just need to decouple my business logic from the composables. In my case I have a coroutine that starts fetching data and when it comes back it sets a value which causes recomposition, but also kicks that coroutine back off again.
a
and here @Adam Powell usually arrives and explains how nicely coroutines work inside composables :)
😄 1
a
I'm also not going to argue against factoring stateful operations into nicely scoped objects with well-defined ownership 🙂