Hi all :android-wave: , I have a code like this, `...
# compose-android
a
Hi all 👋 , I have a code like this,
Copy code
@Composable
fun ScreenComposable() {
  val handleUri = { uri: Uri ->
    // Some code
  }
  val openDocumentResultLauncher: ManagedActivityResultLauncher<Array<String>, Uri?> = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.OpenDocument(),
  ) { uri ->
    uri?.let {
      handleUri()
    }
  }

  // openDocumentResultLauncher is used like this,
  val object = remember {
    SomeClass(
      openDocument = {
        openDocumentResultLauncher.launch(arrayOf(MimeTypeConstants.JSON))
      },
    )
  }
}
In this code,
handleUri
has to be defined before
openDocumentResultLauncher
. Can I rewrite this code in a way that
handleUri
is passed as a parameter (dependency) to
openDocumentResultLauncher
.
openDocument
in
SomeClass
will provide the code for
handleUri
.
i
Caleb's approach doesn't work at all - extras you pass to the other activity aren't sent back to you to parse. Even then, there's no way to have a Serializable that has a lambda
If you look at the implementation of rememberLauncherForActivityResult, you'll see a few important things: 1. You need a unique key that survives process death and recreation (the
rememberSaveable { UUID.randomUUID().toString() }
part) - that's how this actually reconnects consistently 2. Getting the
ActivityResultRegistry
using the
LocalActivityResultRegistryOwner
3. Calling
register
(which is what requires your
handleUri
) and
unregister
in a
DisposableEffect
such that the launcher only exists as long as it exists in composition Technically, those are all pieces you can do yourself, in any place you want. However, I don't think you can do all of that within the
remember
of
SomeClass
a
Hi Ian, Thanks for answering, but I am not clear on what to do or if this is possible. What I want is to move
handleUri
inside
SomeClass
. Currently,
createDocument
callback of
SomeClass
will expose the handler to the parent Composable.
Copy code
createDocument = { handler: (uri: Uri) -> Unit ->
  createDocumentResultLauncher.launch(MimeTypeConstants.JSON)
},
But, I could not figure our how to use the
handler
now. Can you please help thank you color .
I can't move the whole
rememberLauncherForActivityResult
into the
createDocument
as it does not have Composable scope. Also, the
SomeClass
is Compose independent, so I can't make
createDocument
into a Composable lambda.
t
I do use following code for opening documents in Compose:
Copy code
@Composable
fun rememberFilePicker(): FilePickerState {
    val state = remember { MutableFilePickerState() }
    val launcher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.OpenDocument(),
        onResult = { uri: Uri? ->
            state.selectedUri = uri
        }
    )
    state.launcher = launcher
    return state
}

interface FilePickerState {
    val selectedUri: Uri?
    fun launchFilePickerIntent(filter: Array<String>)
}

private class MutableFilePickerState() : FilePickerState {
    var launcher: ManagedActivityResultLauncher<Array<String>, Uri?>? = null
    override var selectedUri: Uri? by mutableStateOf(null)
    override fun launchFilePickerIntent(filter: Array<String>) {
        checkNotNull(launcher).launch(filter)
    }
}
Usage in compose is than as follows:
Copy code
val filePicker = rememberFilePicker()
val selectedAudioUri = filePicker.selectedUri
if (selectedAudioUri != null) {
    AudioPane(
        modifier = Modifier.fillMaxSize(),
        audioUri = selectedAudioUri
    )
} else {
    Button(onClick = { filePicker.launchFilePickerIntent(arrayOf("audio/*")) }) {
        Text("Select music file")
    }
}
Not exactly what you ask for. But i am sure you can change the code that it will fit you needs. So you could add a lambda parameter to the remember function that is called when the uri is selected.