Está en la página 1de 18

TEMAS AVANZADOS DE ANDROID

MULTIMEDIA
Temas avanzados de Android

TEMAS AVANZADOS DE ANDROID


MULTIMEDIA

Para proporcionar una experiencia del usuario más enriquecida, muchas apps
permiten que los usuarios contribuyan y accedan al contenido multimedia
disponible en un volumen de almacenamiento externo. El framework proporciona
un índice optimizado para colecciones de contenido multimedia, llamado tienda
de contenido multimedia, que permite recuperar y actualizar esos archivos con
más facilidad. Incluso después de desinstalar la app, los archivos permanecen
en el dispositivo del usuario.

Para interactuar con la abstracción de la tienda de contenido multimedia, usa un


objeto “ContentResolver” que obtengas del contexto de tu app:

El sistema analiza automáticamente un volumen de almacenamiento externo y


agrega archivos multimedia a las siguientes colecciones bien definidas:

• Imágenes, incluidas fotografías y capturas de pantalla, que se almacenan


en los directorios DCIM/ y Pictures/. El sistema agrega estos archivos a la
tabla “MediaStore.Images”.

• Videos, que se almacenan en los directorios DCIM/, Movies/ y Pictures/.


El sistema agrega estos archivos a la tabla “MediaStore.Video”.

• Archivos de audio, que se almacenan en los directorios Alarms/,


Audiobooks/, Music/, Notifications/, Podcasts/ y Ringtones/. Además, el
sistema reconoce listas de reproducción de audio que se encuentran en

1
Temas avanzados de Android

los directorios Music/ o Movies/, además de grabaciones de voz que se


encuentran en el directorio Recordings/. El sistema agrega estos archivos
a la tabla “MediaStore.Audio”. El directorio de grabaciones no está
disponible en Android 11 (nivel de API 30) ni versiones anteriores.
Archivos descargados, que se almacenan en el directorio Download/. En los
dispositivos que ejecutan Android 10 (nivel 29 de API) y versiones posteriores,
estos archivos se almacenan en la tabla “MediaStore.Downloads”. Esta tabla no
está disponible en Android 9 (nivel de API 28) ni en versiones anteriores.

La tienda de contenido multimedia también incluye una colección llamada


“MediaStore.Files”. Su contenido depende de si la app usa el almacenamiento
específico, que está disponible en apps orientadas a Android 10 o versiones
posteriores:
Si el almacenamiento específico está habilitado, la colección solo muestra las
fotos, los videos y los archivos de audio que creó tu app. La mayoría de los
desarrolladores no necesitarán usar “MediaStore.Files” para ver los archivos
multimedia de otras apps, pero si tienes un requisito específico para hacerlo,
puedes declarar el permiso “READ_EXTERNAL_STORAGE”. Sin embargo, es
recomendable usar las API de MediaStore para abrir archivos que la app no haya
creado.

Si el almacenamiento específico no está disponible o no se usa, la colección


muestra todos los tipos de archivos multimedia.

Cómo solicitar los permisos necesarios:

Antes de realizar operaciones en archivos multimedia, tenemos que asegurarnos


de que la app declare los permisos necesarios para acceder a esos archivos. No
obstante, ten en cuenta que la app no debe declarar permisos que no necesita
ni usa.
Permiso de almacenamiento:

El modelo de permisos para acceder a los archivos multimedia en tu app


depende de si esta usa almacenamiento específico, disponible en apps
orientadas a Android 10 o versiones posteriores.
Almacenamiento específico habilitado:

Si nuestra app usa el almacenamiento específico, debe solicitar permisos


relacionados con el almacenamiento solo para dispositivos que ejecuten Android
9 (nivel 28 de API) o versiones anteriores. Para aplicar esta condición,
agregamos el atributo “android:maxSdkVersion” a la declaración de permisos en
el archivo de manifiesto de la app:

2
Temas avanzados de Android

No solicitaremos de manera innecesaria permisos relacionados con el


almacenamiento para dispositivos que ejecutan Android 10 o versiones
posteriores. Nuestra app puede contribuir a colecciones de contenido multimedia
bien definidas, incluida la colección “MediaStore.Downloads”, sin solicitar ningún
permiso relacionado con el almacenamiento. Si estamos desarrollando una app
de cámara, por ejemplo, no necesitas solicitar permisos relacionados con el
almacenamiento porque la app es propietaria de las imágenes que escribes en
la tienda de contenido multimedia.

Para acceder a los archivos que crearon otras apps, se deben cumplir las
siguientes condiciones:

• Se le otorgó el permiso “READ_EXTERNAL_STORAGE” a tu app.

• Los archivos se alojan en una de las siguientes colecciones de contenido


multimedia bien definidas:
o MediaStore.Images.
o MediaStore.Video.
o MediaStore.Audio.

Si nuestra app quiere acceder a un archivo incluido en la colección


“MediaStore.Downloads” que no creó, debes usar el framework de acceso a
almacenamiento.

Almacenamiento específico no disponible:

Si nuestra app se usa en un dispositivo que ejecuta Android 9 o versiones


anteriores, o si se inhabilitó temporalmente el almacenamiento específico,
debemos solicitar el permiso “READ_EXTERNAL_STORAGE” para acceder a
los archivos multimedia. Si deseamos modificar archivos multimedia, también
debemos solicitar el permiso “WRITE_EXTERNAL_STORAGE”.

Permiso de ubicación de contenido multimedia:

3
Temas avanzados de Android

Si nuestra app está orientada a Android 10 (nivel de API 29) o versiones


posteriores, para que recupere metadatos de EXIF sin ocultar de las fotos,
debemos declarar el permiso “ACCESS_MEDIA_LOCATION” en el manifiesto
de nuestra app y, luego, solicitar este permiso durante el tiempo de ejecución.

Cómo buscar actualizaciones de la tienda de contenido multimedia:

Para acceder a los archivos multimedia de manera más confiable, en especial si


nuestra app almacena en caché URI o datos de la tienda multimedia,
comprobamos si cambió la versión de la tienda cuando se sincronizaron los datos
por última vez. Para realizar esta búsqueda de actualizaciones, llamamos a
“getVersion()”. La versión que se muestra es una “string” única que cambia cada
vez que la tienda de contenido multimedia cambia sustancialmente. Si la versión
que se muestra es diferente de la última versión sincronizada, vuelve a analizar
y sincronizar la caché de medios de nuestra app.
Esta verificación la completamos en el momento de inicio del proceso de la app.
No es necesario verificar la versión cada vez que consultamos la tienda de
contenido multimedia.

No supongas ningún detalle de la implementación acerca del número de la


versión.

Cómo buscar una colección de contenido multimedia:


Para encontrar contenido multimedia que cumpla con un conjunto determinado
de condiciones, como una duración de 5 minutos o más, usa una declaración de
selección similar a SQL, parecida a la que se muestra en el siguiente fragmento
de código:

Continúa

4
Temas avanzados de Android

Cuando realicemos una consulta de este tipo en nuestra app, hay que tener en
cuenta lo siguiente:

• Llamar al método “query()” en un subproceso del trabajador.

• Almacenar los índices de columna en caché para no tener que llamar a


“getColumnIndexOrThrow()” cada vez que proceses una fila desde el
resultado de la consulta.

• Agregar el ID al URI de contenido, como se muestra en el fragmento de


código.

5
Temas avanzados de Android

• Los dispositivos que ejecutan Android 10 y versiones posteriores


requieren nombres de columna definidos en la API de MediaStore. Si una
biblioteca dependiente de la app espera un nombre de columna que no
está definido en la API, como "MimeType", usa “CursorWrapper” para
traducir dinámicamente el nombre de la columna en el proceso de la app.

Cómo cargar miniaturas de archivos:

Si la app muestra varios archivos multimedia y solicita que el usuario elija uno de
estos, es más eficiente cargar versiones de vista previa (o miniaturas) de los
archivos, en lugar de los archivos en sí.
Para cargar la miniatura de un archivo multimedia determinado, usa
“loadThumbnail()” y pasa el tamaño de la miniatura que desees cargar, como se
muestra en el siguiente fragmento de código:

Cómo abrir un archivo multimedia:

La lógica específica que usamos para abrir un archivo multimedia depende de si


el contenido multimedia se representa mejor como descriptor de archivos,
transmisión de archivos o ruta de acceso a archivo directa:
Descriptor de archivo:
Para abrir un archivo multimedia con un descriptor de archivo, usa una
lógica similar a la que se muestra en el siguiente fragmento de código:

Transmisión de archivos:
Para abrir un archivo multimedia con una transmisión de archivos, usa una
lógica similar a la que se muestra en el siguiente fragmento de código:

6
Temas avanzados de Android

Rutas de acceso a archivos directas:

Para ayudar a que tu app funcione sin problemas con las bibliotecas
multimedia de terceros, Android 11 (nivel de API 30) y las versiones
posteriores te permiten usar API distintas de la API de MediaStore para
acceder a archivos multimedia desde el almacenamiento compartido. En
su lugar, puedes acceder a los archivos multimedia directamente con
cualquiera de las siguientes API:

• La API de File.
• Bibliotecas nativas, como “fopen()”.
Si no tienes ningún permiso relacionado con el almacenamiento, puedes
acceder a los archivos del directorio específico de la app y a los archivos
multimedia atribuidos a la app; para ello, usa la API de “File”.
Si nuestra app intenta acceder a un archivo con la API de “File” y no tiene
los permisos necesarios, se genera una “FileNotFoundException”.

Para acceder a otros archivos del almacenamiento compartido en un dispositivo


con Android 10 (nivel de API 29), se recomienda que se inhabilite temporalmente
el almacenamiento específico estableciendo “requestLegacyExternalStorage” en
“true” en el archivo de manifiesto de nuestra app. Para acceder a los archivos
multimedia con los métodos de archivos nativos en Android 10, también debes
solicitar el permiso “READ_EXTERNAL_STORAGE”.

Consideraciones para tener en cuenta al acceder a contenido multimedia:


Cuando accedamos a contenido multimedia, hay que tener en cuenta las
consideraciones que se analizan en las siguientes secciones.
Datos almacenados en caché:
Si nuestra app almacena en caché los URI o los datos de la tienda de
multimedia, tenemos que verificar si hay actualizaciones. Esta verificación
permite que los datos almacenados en caché de nuestra app
permanezcan sincronizados con los datos del proveedor del sistema.
Rendimiento:

7
Temas avanzados de Android

Cuando realicemos lecturas secuenciales de archivos multimedia con


rutas de archivos directas, el rendimiento es similar al de la API de
“MediaStore”.

Sin embargo, cuando realizamos lecturas y escrituras aleatorias de


archivos multimedia con rutas de archivos directas, el proceso puede ser
hasta dos veces más lento. En estas situaciones, se recomienda usar la
API de “MediaStore”.
Columna DATA:
Cuando accedemos a un archivo multimedia existente, podemos usar el
valor de la columna DATA en nuestra lógica. Esto se debe a que este valor
tiene una ruta de archivo válida. Sin embargo, no debemos asumir que el
archivo siempre está disponible. Debemos prepararnos para controlar
cualquier error de E/S basado en archivos que se pueda producir.
Por otro lado, para crear o actualizar un archivo multimedia, no usaremos
el valor de la columna “DATA”. En su lugar, usaremos los valores de las
columnas “DISPLAY_NAME y RELATIVE_PATH”.
Volúmenes de almacenamiento:

Las apps orientadas a Android 10 o versiones posteriores pueden acceder


al nombre único que asigna el sistema a cada volumen de
almacenamiento externo. Este sistema de nombres te ayuda a organizar
e indexar el contenido de manera eficiente, y te permite controlar dónde
se almacenan los nuevos archivos multimedia.
Los siguientes volúmenes son particularmente útiles para tener en cuenta:

• El volumen “VOLUME_EXTERNAL” proporciona una vista de todos


los volúmenes de almacenamiento compartido en el dispositivo.
Puedes leer el contenido de este volumen sintético, pero no puedes
modificarlo.

• El volumen “VOLUME_EXTERNAL_PRIMARY” representa el


volumen de almacenamiento compartido principal en el dispositivo.
Puedes leer y modificar el contenido de este volumen.

Ubicación donde se capturó el contenido multimedia:

Algunas fotos y videos contienen información sobre la ubicación en sus


metadatos, que muestra el lugar donde se tomó una fotografía o dónde se
grabó un video.

8
Temas avanzados de Android

Si queremos acceder a esta información de ubicación en nuestra app,


usaremos una API para obtener información de ubicación de fotos y otra
API para obtener información de ubicación de videos.
Uso compartido:

Algunas apps permiten que los usuarios compartan archivos multimedia


entre sí. Por ejemplo, las apps de redes sociales brindan a los usuarios la
capacidad de compartir fotos y videos con amigos.
Para compartir archivos multimedia, usaremos un URI “content://”, que es
lo recomendado.
Atribución de archivos multimedia a apps:

Cuando el almacenamiento específico está habilitado para una app


orientada a Android 10 o versiones posteriores, el sistema atribuye cada
archivo multimedia a una app, lo que determina los archivos a los que
puede acceder nuestra app si no solicitó ningún permiso de
almacenamiento. Se puede atribuir cada archivo a una sola app. Por lo
tanto, si nuestra app crea un archivo multimedia que se almacena en la
colección de contenido multimedia de fotos, videos o archivos de audio, la
app tendrá acceso al archivo.

Sin embargo, si el usuario desinstala y reinstala tu app, debes solicitar el


permiso “READ_EXTERNAL_STORAGE” para acceder a los archivos
que la app creó originalmente. Esta solicitud es obligatoria porque el
sistema considera que se atribuye el archivo a la versión instalada
previamente de la app, en lugar de a la que se instaló recientemente.

9
Temas avanzados de Android

Cómo agregar un artículo:

Para agregar un elemento multimedia a una colección existente, llamaremos a


un código similar al siguiente:

Como vemos este fragmento de código nos permite acceder al volumen


“VOLUME_EXTERNAL_PRIMARY” en dispositivos con Android 10 o versiones
posteriores. Esto se debe a que, en estos dispositivos, solo puedes modificar el
contenido de un volumen si es el principal.

Cómo activar o desactivar el estado pendiente para archivos multimedia:

Si la app realiza operaciones que pueden tardar mucho tiempo, como escribir en
archivos multimedia, resulta práctico contar con acceso exclusivo al archivo
mientras se procesa. En dispositivos que ejecutan Android 10 o versiones
posteriores, la app puede obtener ese acceso exclusivo si establece el valor de
la marca “IS_PENDING” en 1. Solo tunuestra app podrá ver el archivo hasta que
cambie nuevamente el valor de “IS_PENDING” a 0.

En el siguiente fragmento de código, se muestra el ejemplo en mayor detalle del


fragmento de código anterior. Ese fragmento muestra cómo usar la marca
“IS_PENDING” cuando se almacena una canción larga en el directorio
correspondiente a la colección “MediaStore.Audio”.

10
Temas avanzados de Android

Cómo brindar sugerencias sobre la ubicación de archivos:

Cuando nuestra app almacena contenido multimedia en un dispositivo que


ejecuta Android 10, se organiza ese contenido de forma predeterminada según
el tipo. Por ejemplo, se colocan los archivos de imagen nuevos de forma
predeterminada en el directorio “Environment.DIRECTORY_PICTURES”, que
corresponde a la colección “MediaStore.Images”.
Si la app conoce la ubicación específica donde se deben almacenar los archivos,
como un álbum de fotos llamado “Fotos/MisFotosdeVacaciones”, podemos
establecer “MediaColumns.RELATIVE_PATH” para sugerir al sistema dónde
almacenar archivos recién escritos.

11
Temas avanzados de Android

Cómo actualizar un elemento:

Para actualizar un archivo multimedia de propiedad de nuestra app,


ejecutaremos un código similar al siguiente:

Si el almacenamiento específico no está disponible o habilitado, el proceso que


se muestra en el fragmento de código anterior también funcionará para los
archivos que no son de la app.

Actualización en código nativo:


Si necesitamos escribir archivos multimedia con bibliotecas nativas, pasaremos
el descriptor de archivo asociado del archivo desde el código basado en Java o
Kotlin al código nativo.

En el siguiente fragmento de código, se muestra cómo pasar el descriptor de


archivos de un objeto multimedia al código nativo de la app:

12
Temas avanzados de Android

Actualiza los archivos multimedia de otras apps:

Si nuestra app usa almacenamiento específico, por lo general no podrá actualizar


un archivo multimedia que otra app colocó en el almacenamiento multimedia.

Sin embargo, es posible obtener el consentimiento del usuario para modificar el


archivo si se captura la “RecoverableSecurityException” que arroja la plataforma.
Luego puedes pedirle al usuario que le permita a nuestra app realizar las
operaciones de escritura en ese elemento específico, como se muestra en el
siguiente fragmento de código:

Completaremos este proceso cada vez que nuestra app necesite modificar un
archivo multimedia que no creó.

De manera alternativa, si nuestra app se ejecuta en Android 11 o versiones


posteriores, podemos permitir que los usuarios otorguen acceso de escritura a
un grupo de archivos multimedia. Llamaremos al método “createWriteRequest()”.
Si nuestra app tiene otro caso de uso que no se incluye en el almacenamiento
específico, enviaremos una solicitud de función y, luego, inhabilitaremos el
almacenamiento específico de forma temporal.

Cómo quitar un elemento:

Para quitar un elemento que nuestra app ya no necesita en la tienda de contenido


multimedia, usaremos una lógica similar a la que se muestra en el siguiente
fragmento de código:

13
Temas avanzados de Android

Si el almacenamiento específico no está disponible o habilitado, podemos usar


el fragmento de código anterior para quitar los archivos que pertenecen a otras
apps. Sin embargo, si el almacenamiento específico está habilitado, deberemos
capturar una “RecoverableSecurityException” para cada archivo que la app
desea quitar.

Si nuestra app se ejecuta en Android 11 o versiones posteriores, podemos


permitir que los usuarios elijan un grupo de archivos multimedia para quitarlos.
Para realizar esto llamaremos al método “createTrashRequest()” o al método
“createDeleteRequest()”.

Si nuestra app tiene otro caso de uso que no se incluye en el almacenamiento


específico, enviaremos una solicitud de función y, luego, inhabilitaremos el
almacenamiento específico de forma temporal.

Cómo detectar actualizaciones de archivos multimedia:

Es posible que nuestra app necesite identificar volúmenes de almacenamiento


con archivos multimedia que las apps agregaron o modificaron, en comparación
con un momento anterior. Para detectar estos cambios de forma más confiable,
pasaremos el volumen de almacenamiento de interés a “getGeneration()”.
Siempre que la versión de la tienda de contenido multimedia no cambie, el valor
que se muestra de este método aumenta de forma monotónica con el tiempo.

En particular, “getGeneration()” es más estable que las fechas en las columnas


de medios, como “DATE_ADDED” y “DATE_MODIFIED”. Eso se debe a que
esos valores de columna de contenido multimedia pueden cambiar cuando una
app llama a “setLastModified()” o cuando el usuario cambia el reloj del sistema.

14
Temas avanzados de Android

Cómo administrar grupos de archivos multimedia:

En Android 11 y versiones posteriores, podemos pedirle al usuario que


seleccione un grupo de archivos multimedia y, luego, que los actualice en una
sola operación. Estos métodos ofrecen una mejor coherencia entre dispositivos
y permiten que los usuarios administren sus colecciones de contenido multimedia
con mayor facilidad.
Los métodos que proporcionan esta funcionalidad de "actualización por lotes"
incluyen los siguientes:

• createWriteRequest()

Solicita al usuario que otorgue acceso de escritura a la app para el grupo


especificado de archivos multimedia.

• createFavoriteRequest()

Solicita al usuario que marque los archivos multimedia especificados


como algunos de sus archivos multimedia "favoritos" en el dispositivo.
Cualquier app que tenga acceso de lectura a este archivo podrá ver que
el usuario marcó el archivo como "favorito".

• createTrashRequest()

Solicita al usuario que coloque los archivos multimedia especificados en


la papelera del dispositivo. Se borran de forma permanente los elementos
de la papelera después de un período definido por el sistema.

• createDeleteRequest()

Solicita al usuario que borre de forma permanente e inmediata los


archivos multimedia especificados, sin colocarlos antes en la papelera.
Después de llamar a cualquiera de estos métodos, el sistema compila un objeto
“PendingIntent”. Una vez que nuestra app invoca este “intent”, los usuarios ven
un diálogo que solicita su consentimiento para que nuestra app actualice o borre
los archivos multimedia especificados.

Por ejemplo, aquí se muestra cómo estructurar una llamada a


“createWriteRequest()”:

15
Temas avanzados de Android

Evalúa la respuesta del usuario. Si el usuario otorgó su consentimiento, continúa


con la operación multimedia. De lo contrario, explícale al usuario por qué tu app
necesita el permiso:

Podemos usar este mismo patrón general con “createFavoriteRequest()”, con


“createTrashRequest()” y con “createDeleteRequest()”.

Permiso para administrar contenido multimedia:

Los usuarios pueden confiar en que una app determinada llevará a cabo la
administración del contenido multimedia, por ejemplo, realizará, con frecuencia,
cambios en los archivos multimedia. Si la app se orienta a Android 11 o versiones
posteriores, y no es la galería predeterminada del dispositivo, deberemos
mostrarle un diálogo de confirmación al usuario cada vez que nuestra app intente
modificar o borrar un archivo.

Si nuestra app se orienta a Android 12 (nivel de API 31) o una versión posterior,
podremos solicitar que los usuarios otorguen acceso a nuestra app al permiso
especial de Administración de medios. Este permiso permite que nuestra app
realice una de las siguientes acciones sin necesidad de solicitarle al usuario cada
operación de archivo:

• Modificar archivos, mediante “createWriteRequest()”.

• Mover archivos a la papelera y sacarlos, mediante “createTrashRequest()”.

• Borrar archivos, mediante “createDeleteRequest()”.


Para ello, completaremos los siguientes pasos:

1. Declarar el permiso de “MANAGE_MEDIA” y declarar el permiso de


“READ_EXTERNAL_STORAGE” en el archivo de manifiesto de la app.

Para llamar a “createWriteRequest()” sin mostrar un diálogo de


confirmación, también declarar el permiso “ACCESS_MEDIA_LOCATION”.

16
Temas avanzados de Android

2. En la app, mostraremos al usuario una IU para explicarle por qué es


posible que desee otorgarle a la app el acceso a la administración del
contenido multimedia.

3. Invocaremos la acción de intent “ACTION_REQUEST_MANAGE_MEDIA”,


que lleva a los usuarios a la pantalla Apps de administración de
multimedia en la configuración del sistema. En esta pantalla, los usuarios
pueden otorgar el acceso especial de apps.

Casos prácticos que requieren una alternativa a la tienda de contenido


multimedia:

Si nuestra app realiza principalmente una de las siguientes funciones,


procuraremos contar con una alternativa a las API de “MediaStore”.
Cómo trabajar con otros tipos de archivos:

Si nuestra app trabaja con documentos y archivos que no incluyen


exclusivamente contenido multimedia, como archivos que usan la extensión
EPUB o PDF, utilizaremos la acción de intent “ACTION_OPEN_DOCUMENT”.
Cómo compartir archivos en apps complementarias:

En los casos en los que proporcionemos un conjunto de apps complementarias


(como una app de mensajería y una app de perfil), deberemos configurar el uso
compartido de archivos mediante los URI de content://. Este flujo de trabajo es
la práctica recomendada de seguridad.

17

También podría gustarte