ReactiveCircus/FlowBinding

Activity Result API

brewin opened this issue · 2 comments

I wonder if it would be possible to add bindings for the new Activity Result API? It would be nice to have if there's a clean way to do it.

I made a quick attempt, but it doesn't work because registerForActivityResult must be called before STARTED and there doesn't seem to be any way to add callbacks after registering.

fun <I, O> ActivityResultCaller.activityResults(contract: ActivityResultContract<I, O>) = callbackFlow {
        val launcher = registerForActivityResult(contract) { result ->
            safeOffer(result)
        }
        awaitClose { launcher.unregister() }
    }

fun <I, O> ActivityResultCaller.launchForActivityResults(contract: ActivityResultContract<I, O>, input: I) =
    registerForActivityResult(contract) {}.launch(input)

LifecycleOwner is attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED

Nice work on the 1.0 release!

I'm not familiar with the Activity Result API, but looks like you have to hold onto the launcher: ActivityResultLauncher object to call launch() separately? So I'm not sure how we can abstract this workflow in a single Flow.

You're right. I was thinking multiple callbacks would be called for the same contract with different launchers. But that's not the case. So I guess there isn't any clean way to do it with a single extension function.

I ended up just using a MutableSharedFlow.

class MainActivity : AppCompatActivity() {
    
    private val permissionsResults = MutableSharedFlow<Map<String, Boolean>>(1)
    private val permissionsLauncher = registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions(),
        permissionsResults::tryEmit
    )

    ...

For fun, here's an ugly way to do it with a single extension function...

class LauncherAndResults<I, O>(val launcher: ActivityResultLauncher<I>, val results: Flow<O>)

fun <I, O> ActivityResultCaller.launcherAndResults(
    contract: ActivityResultContract<I, O>
): LauncherAndResults<I, O> {
    val results = MutableSharedFlow<O>(1)
    val launcher = registerForActivityResult(contract, results::tryEmit)
    return LauncherAndResults(launcher, results)
}