如何使用 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。
我正在构建一个 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。