Is anyone using `rememberLauncherForActivityResult...
# compose
c
Is anyone using
rememberLauncherForActivityResult
and Compose Navigation?
I’m a bit unsatisfied with code like this:
Copy code
@Composable
fun MyNavHost() {
  val launcher = rememberLauncherForActivityResult(contract = ...) { result ->
    // handle 'result'
  }

  NavHost(...) {
    composable(...) {
      MyScreen(onClick = { launcher.launch(...) })
    }
  }
}
My assumption is that we would want a 1-1 relationship between an ActivityResultLauncher and a nav graph Destination. Right? This trivial example is fine, but if you add more and more screens (most of which do not rely on a launcher), and more launchers (photos, permissions, whatever), it’s hard to tightly scope the related concerns. I would like to have code where the
onResult
callback is adjacent to the definition of the Destination.
I tried to make a custom navigator
Copy code
class ActivityResultNavigator : Navigator<ActivityResultNavigator.Destination>()
But I’m not sure what to do about the ActivityResultLauncher. Using
rememberLauncherForActivityResult
doesn’t really help since it has the same problem as my above sample code. That is, I can’t create the launcher adjacent to the Destination, because it relies on a Composable context. I could define my own ActivityResultLauncher but I’m unsure how to manage its lifecycle in the context of Navigation and Compose.
I’d appreciate any feedback or suggestions. Am I looking at this the wrong way?
a
What’s preventing putting
rememberLauncherForActivityResult
inside
MyScreen
? Or perhaps right next to
MyScreen
inside the
composable(...) {
block.
rememberLauncherForActivityResult
internally handles the lifecycle considerations automatically, so you’re free to define it locally where you need it. (That is a notable difference from the non-Compose world with activity results, where you have to be more careful about always creating them in the same order)
☝️ 1
i
Well, it really isn't any different from whether you create your launcher at the Activity level vs in an individual fragment level - you'd create it at the level you use it at. It is just that every Composable is just as power as any other one, so declare it where you need it
Which means you could write it as
Copy code
composable(...) {
  val launcher = rememberLauncherForActivityResult(contract = ...) { result ->
    // handle 'result'
  }
  MyScreen(onClick = { launcher.launch(...) })
}
or put it inside
MyScreen
c
Hold on, perhaps I have misunderstood something else. The docs for
registerForActivityResult
say
This must be called unconditionally, as part of initialization path, typically as a field initializer of an Activity or Fragment.
This led me to conclude that I could not call this (via
rememberLauncherForActivityResult
) within a composable screen. But I didn’t test it; I just assumed.
If I can put it in the composable() block, that’s much better
Thanks for responding!
i
it still needs to be called unconditionally in your composable (i.e., not within an
if
block - just like any other
remember
method, it would be forgotten if not part of your ouput)
it is more that the positioning within the composable that matters, as it relies on
rememberSaveable
under the hood
c
Yeah it was the “as part of initialization path” that threw me. Thanks for the help
484 Views