https://kotlinlang.org logo
#compose
Title
# compose
m

manueldidonna

09/12/2020, 4:18 PM
I tried to adapt the Activity Result api to compose but I don't think I've done a good job 😅 It works, but I believe there is a better way to do it. Any suggestions?
Copy code
@Stable
@Composable
fun <I, O> activityResultLauncher(
    contractKey: String,
    contract: ActivityResultContract<I, O>,
    activityResultCallback: ActivityResultCallback<O>,
): ActivityResultLauncher<I> {
    val lifecycleOwner = LifecycleOwnerAmbient.current
    val registry = ActivityResultRegistryAmbient.current
    val launcher = remember(contract, registry, contractKey) {
        registry.register(contractKey, lifecycleOwner, contract, activityResultCallback)
    }
    onDispose {
        launcher.unregister()
    }
    return launcher
}

@Composable
fun ImportSaveDataFromFile(onImport: (SaveData?) -> Unit) {
    val context = ContextAmbient.current
    var launchActivity by savedInstanceState { false }
    val activityLauncher = activityResultLauncher("ImportSaveData", OpenDocumentContract) { uri: Uri? ->
        onImport(createSaveData(uri, context))
    }
    if (launchActivity) {
        launchActivity = false
        activityLauncher.launch(arrayOf("*/*"))
    }
    Surface(modifier = Modifier.fillMaxSize()) {
        Button(
            modifier = Modifier.fillMaxSize().wrapContentSize(Alignment.Center),
            onClick = { launchActivity = true }
        ) {
            Text(text = "IMPORT SAVE DATA")
        }
    }
}
a

Adam Powell

09/12/2020, 4:23 PM
avoid the
launchActivity
state. That's not state, it's an event
just call the
activityLauncher.launch
in your
onClick
m

manueldidonna

09/12/2020, 5:02 PM
I agree, it was an easily avoidable mistake. Thanks!
I've found a strange behavior. I don't know if it's a bug. I've cliked on the import button, the activity picker has been launched than I rotated the screen and I selected the file. The 'onImport' callback is called but the screen isn't recomposed. This is the code of my main activity
Copy code
private object MainState {
        var saveData by mutableStateOf<SaveData?>(null)
        var currentScreen by mutableStateOf<MainScreen>(MainScreen.Root)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MaterialTheme {
                Providers(ActivityResultRegistryAmbient provides activityResultRegistry,) {
                    val saveData: SaveData? = MainState.saveData
                    if (saveData == null) {
                        ImportSaveDataFromFile {
                            // this is the 'onImport' callback of the precedent code snippet.
                            // this callback is invocked, the 'it' object is the right object but MainScreen
                            // in the else statement doesn't show until I rotate the activity again
                            MainState.saveData = it
                        }
                    } else {
                        MainScreen(saveData = saveData)
                    }
                }
            }
        }
    }
@Adam Powell The bug happens here. MainState.saveData is updated but the composition isn't invoked, "create" isn't printed in the logcat after the state change. This happen only if I rotate the activity while picking the file
Copy code
val saveData: SaveData? = MainState.saveData
                    Log.d("intent", "create")
                    if (saveData == null) {
                        ImportSaveDataFromFile {
                            MainState.saveData = it
                            Log.d("intent","savedata: ${MainState.saveData}")
                        }
                    } else {
                        MainScreen(
                            screen = MainState.currentScreen,
                            saveData = saveData,
                            events = this
                        )
                    }
s

Sean McQuillan [G]

09/14/2020, 6:13 PM
Not sure the minimal repro here looking at it
Here's an earlier exploration I did of the activity result API – it might help debugging what's going on
My immediate suspicion is that the state isn't actually getting set, or is getting reset before the next composition
4 Views