Android ActivityResultContracts.CreateDocument onResult is never called

834 Views Asked by At

In my app it is supposed that users can choose a path to save their texts through SAF. I use ActivityResultContracts.CreateDocument to do this, which will provide the Uri of the created file so that I can operate on that file, such as writing contents to its outputStream. However, although the file is created successfully, its content is empty. it seems that the callback, in which I write contents with the given Uri, is never called. The codes are not running, and the logs are not printed. I looked up the official documents and forums, trying to find examples of ActivityResultContracts.CreateDocument and found nothing but that the constructor I used to create the contract, which receives no argument, is deprecated and replaced by a new one that requires mime type of the created file like:

public final CreateDocument(@NonNull String mimeType)

However, in my Anroid Studio I can only find and use the deprecated constructor like following:

@RequiresApi(19)
    open class CreateDocument : ActivityResultContract<String, Uri?>() {
        ...
    }

I wonder if it's the reason behind the not-working onResult callback, or it's because my codes meet some problems, and how I can solve this problem. My codes are below:

// WriteScreen.kt(Composable)
// Launched after clicking a button.
val saveFile = rememberLauncherForActivityResult(ActivityResultContracts.CreateDocument()) { uri ->
        Log.d(TAG, "WriteScreen: Enter callback onResult of saveFile launcher")
        uri?.let { viewModel.saveFileAs(it) }
    }

...

// WriteViewModel.kt
fun saveFileAs(uri: Uri) {
        Log.d(TAG, "saveFileAs: enter method saveFileAs")
        viewModelScope.launch(Dispatchers.IO) {
            Application.context.contentResolver.openOutputStream(uri)?.writer()?.run {
                write(_uiState.value.content)
                flush()
                close()
                Log.d(TAG, "saveFileAs: saved content: ${_uiState.value.content}")
            }
        }
    }

My targetSdkVersion is 32, and compose version is 1.2.0-beta02.

1

There are 1 best solutions below

0
On

I reviewed my codes and found the reason why my codes do not work.

First, the reason why logs are not printed may be that my version of activity-compose(1.4.0) is not the latest(1.5.0 or 1.6.0). I'm not quite sure of this, but they got printed after I updated the version.

As for why nothing is written into the created file, it turns out that returning from SAF will automaticlly trigger recomposition, and in my case it will cause preloading emtpy data from dataSource, which will overwrite data in uiState held by viewModel. And these all happen before entering coroutine, since launch will suspend coroutine and continue running codes in a non-blocking manner. Thus, after entering coroutine, viewModel can only get empty value from uiState, leading to nothing written into file. Surely this will be a lesson for me.