rememberLauncherForActivityResult causes composable to lose state?

Viewed 436

Let's say I've the following code:

@Composable
fun Widget() {
    var text1 by remember { mutableStateOf("DEFAULT") }
    
    val picker = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.GetMultipleContents(),
        onResult = {
            for (uri in it) print(uri)
        },
    )
    
    Text(
        text = text1,
    )
    Button(
        onClick = { text1 = "CHANGED" },
    ) {
        Text(
            text = "Change text1",
        )
    }
    Button(
        onClick = { picker.launch("image/*") },
    ) {
        Text(
            text = "Launch Picker",
        )
    }
}

When my application is installed and launched for the first time if you change the text1 by pressing on the button labeled 'Change text1' and then press the button to launch the picker the composable state is lost and text1 reverts to "DEFAULT".

What is interesting is this happens only for the first time after installing and launching the app or after restarting the phone and using the app for the first time.

I also like to point out that this happens in both debug and release versions of the app.

So, I would like to know what could be the cause of this? is this a known compose bug? or is it how I instantiate/use the picker?

2 Answers

I think there might be a configuration change happening just the first time, which remember does not handle.

Try replacing remember with rememberSaveable. From docs:

While remember helps you retain state across recompositions, the state is not retained across configuration changes. For this, you must use rememberSaveable. rememberSaveable automatically saves any value that can be saved in a Bundle. For other values, you can pass in a custom saver object.

As the other answer already explains, remember is not enough to keep the object between configuration changes.

If you need to keep a complex object you can use rememberScoped with this library: https://github.com/sebaslogen/resaca

This is an alternative to rememberSaveable so you don't need to implement Parcelable nor Saver interfaces, but it won't keep the object between process deaths.

Related