Hey, did anyone experienced a weird behaviour of t...
# compose-ios
a
Hey, did anyone experienced a weird behaviour of the Compose UI when open a camera from the application ? For me, application state just resets whenever the user cancels or takes a picture using a camera, so the application just "reloads" and loses all the data, looks like application has been closed and opened again
βž• 1
P.S. I'm using
UIImagePickerController
and I see that callback of the delegate got invoked, but when the camera UI dismisses, the application just resets its state (or reloads)
P.P.S. It works perfectly with the gallery (same code, but different
sourceType
which is weird)
d
Hello Andrii which navigation library are you using
a
Hi, I'm using my custom implementation which is basically have two classes, one for the logic part which holds destination and transition parameters using
MutableStateFlow
and the other one, which is more UI related, it observes the
StateFlow
and executes transition to a new destination by using the
AnimatedContent
Compose function. The thing that even I have my "logical" part of the navigation under the
remember
I see in the logs that it got reinstantiated. Here how the instantiation of the navigation "router" looks like:
Copy code
@Composable
fun <D> rememberNavigationState(
    mapper: ((D) -> KClass<out ViewModel>?)? = null,
    initialConfiguration: TransitionScope.(NavigationState<D>) -> Unit = {},
    initialDestination: D,
    flowFinalizer: FlowFinalizer,
): NavigationState<D> {
    val manager = LocalViewModelManager.current
    return remember {
        NavigationState(
            initialDestination = initialDestination,
            initialConfiguration = initialConfiguration,
            viewModelExtension = mapper?.let { ViewModelExtension(manager = manager, mapping = it) },
            flowFinalizer = flowFinalizer
        )
    }
}
d
With a life cycle aware library such as Decompose I am able to preserve the current state of the screen , i am able to open the camera and take a number of pictures while preserving the current state of the screen , the ui is not recomposed
πŸ‘€ 2
u
I’m experiencing the exact same issue. https://github.com/TEAM-PREAT/peekaboo/issues/15
a
@원석, it's a compose UI bug for iOS, firstly reported here
βœ”οΈ 2
t
Same issue here. It seems keeping your state outside of compose seems to work. So create your navigation state outside of ComposeUIViewController and then pass it down.
πŸ‘€ 1
I wonder if there is a way to get
rememberSaveable
working on iOS so all state can be kept or so.
a
Thanks. will try thit approach
t
@Andrii Yanechko in your case, create NavigationState outside of ComposeUIViewController
πŸ‘ 1
But keep in mind that on Android you still need to remember it
βœ… 1
Found a way to get saveable state working (e.g. rememberSaveable) on iOS which should help a lot with this issue.
Copy code
class IosSaveableStateFix {
    private var registry = SaveableStateRegistry(restoredValues = null) { true }

    @Composable
    fun Provider(
        block: @Composable () -> Unit
    ) {
        CompositionLocalProvider(LocalSaveableStateRegistry provides registry) {
            block()
        }
        DisposableEffect(Unit) {
            onDispose {
                val savedData = registry.performSave()
                registry = SaveableStateRegistry(restoredValues = savedData) { true }
            }
        }
    }
}
usage:
Copy code
val saveableStateFix = IosSaveableStateFix()
return ComposeUIViewController {
    saveableStateFix.Provider {
        // your app
    }
}
This should fix most state issues because on Android you should already be using rememberSaveable for saving important state like navigation state. Compose itself already uses this a lot for all the views. If you also want to keep viewmodels you still need to save them outside ComposeUIViewController like I showed. (or maybe using rememberSaveable if only targeting iOS?) Keep in mind I have not really tested this code that well, but it seems to work fine for me.
With the above workaround, state is not lost, but saved/restored, which should be similar to how an Android app can be killed and then restored. So not perfect, but better