Migración simple a almacenamiento con alcance | Por Mino Mesa | Marzo de 2022
En este post veremos cómo funciona la migración a Scoped Storage, no voy a explicar los motivos de la decisión de Scoped Storage, las diferencias entre los directorios before y after, ni de qué se trata y cuáles son sus ventajas. , hay muchos recursos que se pueden aprender y puedes encontrarlos fácilmente con una simple búsqueda.me gusta esta.
la primera cosa
tendrás que quitar android:preserveLegacyExternalStorage=”true”
Si lo está utilizando, configure compileSdkVersion
y targetSdkVersion
a 29 o superior y tener los siguientes permisos en su manifiesto de la siguiente manera:
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Si está utilizando la última versión del complemento Gradle, será
compileSdk
ytargetSdk
Se trata de la tienda de medios
Si no está familiarizado con MediaStore
que es la forma principal de guardar archivos usando el almacenamiento con alcance, es posible que se pregunte: ¿cómo usará mi aplicación el almacenamiento con alcance (Android 11+) y tendrá compatibilidad con versiones anteriores si el método que estoy usando lo requiere? android:preserveLegacyExternalStorage=”true”
• Especialmente cuando se trabaja con múltiples imágenes.
La buena noticia es: MediaStore
No nuevo.Como ocurre con muchas cosas en Android, hay muchas formas de lograr lo mismo con un código diferente, como este entrada en el blog Muestra cómo guardar archivos de diferentes maneras. MediaStore
Pero usando nuestro método directamente, para hacer que su aplicación se ejecute en dispositivos por debajo de API 29, puede usar MediaStore.Images.Media.EXTERNAL_CONTENT_URI
si miras Documentación Para ello, verá que existe desde la API 1. Entonces, podemos agregar fácilmente una verificación de la versión del sistema operativo como esta:
fun createImageUri(activity: Activity): Uri? {val imageFileName = "test_"val imagesCollection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Images.Media.getContentUri(
MediaStore.VOLUME_EXTERNAL_PRIMARY
)
} else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
val newImageDetails = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, "$imageFileName.png")
put(MediaStore.Images.Media.MIME_TYPE, "image/png")
}
return activity.applicationContext.contentResolver.insert(imagesCollection, newImageDetails)
}
Aquí estamos creando un
Uri
Para los archivos que usan contentResolver, solo necesita proporcionar información sobre el archivo, como el nombre y el tipo del archivo.
Anteriormente solíamos crear un File
objeto en lugar de Uri
pero si solo usa imágenes, probablemente haya estado usando Uri
ya, pero esto puede ser diferente de otros tipos, puede usar directamente File
siempre ha sido un objeto.El siguiente fragmento muestra cómo crear un Uri
Para video el proceso es el mismo, solo necesitas usar la clase correspondiente, en este caso para el video tenemos MediaStore.Video
podemos usarlo así:
fun createVideoFile(activity: Activity): Uri? {
val videoFileName = "test_"
val videosCollection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Video.Media.getContentUri(
MediaStore.VOLUME_EXTERNAL_PRIMARY
)
} else {
MediaStore.Video.Media.EXTERNAL_CONTENT_URI
}val newVideoDetails = ContentValues().apply {
put(MediaStore.Video.Media.DISPLAY_NAME, "$videoFileName.mp4")
put(MediaStore.Images.Media.MIME_TYPE, "video/mp4")
}
return activity.applicationContext.contentResolver.insert(videosCollection, newVideoDetails)
}
El mismo proceso se utilizará para diferentes tipos de archivos, como audio.
Nota: Recuerda que lo ideal es que cada archivo que crees tenga un nombre diferente.
como viste MediaStore
En realidad, es más fácil que el enfoque en la publicación del blog mencionado anteriormente, ya que para los archivos que no son imágenes, la principal diferencia es probablemente MediaStore
usarás Uri
todo el tiempo en lugar de File
debe aceptar su uso, siempre hay una manera de resolver el problema Uri
y no es necesario obtener la URL/ruta real de la ubicación del archivo como se hizo File
objetar para hacer cosas como obtener miniaturas de video, aquí hay un ejemplo Uri
:
fun getThumbVideo(context: Context, videoUri: Uri): Bitmap? {
var bitmap: Bitmap? = null
var mediaMetadataRetriever: MediaMetadataRetriever? = null
try {
mediaMetadataRetriever = MediaMetadataRetriever()
mediaMetadataRetriever.setDataSource(context, videoUri)
bitmap = mediaMetadataRetriever.getFrameAtTime(
1000,
MediaMetadataRetriever.OPTION_CLOSEST_SYNC
)
} catch (e: Exception) {
e.printStackTrace()
} finally {
mediaMetadataRetriever?.release()
}
return bitmap
}
Si desea información adicional sobre el archivo, puede utilizar ContentResolver
aquí hay un ejemplo para obtener el nombre del archivo en caso de que lo elija en lugar de crearlo:
private fun getFileName(uri: Uri): String? {
var result: String? = null
val cursor = baseActivity?.contentResolver?.query(uri, null, null, null, null)
cursor?.use {
if (cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
}
}
return result
}
En conclusión
te darás cuenta con Uri
En realidad, es muy conveniente desde el principio, ya que se pueden usar la mayoría de las API de archivos Uri
Del mismo modo, por ejemplo, operaciones de archivo como ACTION_IMAGE_CAPTURE
, ACTION_VIDEO_CAPTURE
necesito uno Uri
como parámetro en el arranque o puesta en marcha startActivityForResult
y «agregar» el archivo a Uri
Lo creó anteriormente, solo necesita verificar que la operación fue exitosa para realizar una acción en el archivo, como mostrarlo.Si está enviando archivos a algún almacenamiento en la nube, no necesita preocuparse, ya que todo el almacenamiento en la nube o las bibliotecas de terceros deben proporcionar una API para manejar los archivos. Uri
.
Si necesita recursos de código y más ejemplos, este video me pareció excelente: