如何使用 MediaStore 从 FirebaseStorage 下载媒体文件到本地存储?

How to download a media file from FirebaseStorage to local storage using MediaStore?

我正在构建一个 android 应用程序,为此我必须使用适用于 AndroidQ 及更高版本的 MediaStore 从 FirebaseStorage 下载媒体到本地存储。为此,我参考 this and this.

编写了下面的代码
@RequiresApi(Build.VERSION_CODES.Q)
suspend fun downloadMedia(model: Message): Uri {
    Log.d(TAG, "downloadMedia: Q")
    val fileName = "SK ${model.timeStamp}.jpg"
    val dirPath = "${Environment.DIRECTORY_PICTURES}/Skara"
    val mimeType = "image/jpg"
    val collectionUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)

    val values = ContentValues().apply {
        put(MediaStore.Video.Media.DISPLAY_NAME, fileName)
        put(MediaStore.Video.Media.RELATIVE_PATH, dirPath)
        put(MediaStore.Video.Media.MIME_TYPE, mimeType)
        put(MediaStore.Video.Media.IS_PENDING, 1)
    }

    val uri = contentResolver.insert(collectionUri, values)!!
    try {
        Firebase.storage.getReferenceFromUrl(model.mediaUrl).getFile(uri).await()
    } catch (e: StorageException) {
        Log.d(TAG, "downloadMedia: StorageException")
        Log.d(TAG, "downloadMedia: $uri")
        Log.d(TAG, "downloadMedia: ${e.message}")
        Log.d(TAG, "downloadMedia: ${e.cause}")
    }
    values.apply {
        clear()
        put(MediaStore.Video.Media.IS_PENDING, 0)
    }
    contentResolver.update(uri, values, null, null)
    return uri
}

但是此代码记录了以下错误。

2020-12-08 15:18:38.602 8124-8201/com.skb.skara D/MessageActivity: downloadMedia: Q
2020-12-08 15:18:39.872 8124-8201/com.skb.skara D/MessageActivity: downloadMedia: StorageException
2020-12-08 15:18:39.876 8124-8201/com.skb.skara D/MessageActivity: downloadMedia: content://media/external/images/media/680
2020-12-08 15:18:39.879 8124-8201/com.skb.skara D/MessageActivity: downloadMedia: An unknown error occurred, please check the HTTP result code and inner exception for server response.
2020-12-08 15:18:39.881 8124-8201/com.skb.skara D/MessageActivity: downloadMedia: java.io.IOException: No such file or directory

我不知道错误的原因是什么以及如何解决。请帮我。我有 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 权限。它还在 'Pictures' 文件夹中创建了 'Skara' 文件夹,但该文件夹是空的。

我终于找到了一些工作代码。 (如果有人知道更好的选择,请回答)。

@RequiresApi(Build.VERSION_CODES.Q)
suspend fun downloadMedia(model: Message): Uri {
    val fileName = "SK ${model.timeStamp}.jpg"
    val dirPath = "${Environment.DIRECTORY_PICTURES}/Skara"
    val mimeType = "image/jpg"
    val collectionUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)

    val values = ContentValues().apply {
        put(MediaStore.Video.Media.DISPLAY_NAME, fileName)
        put(MediaStore.Video.Media.RELATIVE_PATH, dirPath)
        put(MediaStore.Video.Media.MIME_TYPE, mimeType)
        put(MediaStore.Video.Media.IS_PENDING, 1)  // This indicates that, the file is not available for other processes until you reset it back to 0.
    }

    val uri = contentResolver.insert(collectionUri, values)!!
        contentResolver.openOutputStream(uri)?.use { ops ->
            Firebase.storage.getReferenceFromUrl(model.mediaUrl).stream.await().stream.use { ips ->
                val buffer = ByteArray(1024)
                while (true) {
                    val bytes = ips.read(buffer)
                    if (bytes == -1)
                        break
                    ops.write(buffer, 0, bytes)
                }
                // The above seven lines can be written in a single line as below. (from 'val buffer' to '}')
                // ips.copyTo(ops) - Kotlin extension function
            }
        }

    values.apply {
        clear()
        put(MediaStore.Video.Media.IS_PENDING, 0)  // Resetting back to zero after the download completes.
    }
    contentResolver.update(uri, values, null, null)
    return uri
}

不过,我对这个答案有疑问,我已经问过 here