Inicio Android Google Drive en Android (2)

Google Drive en Android (2)

por sgoliver
drive-2

[mensaje-curso]

En el art铆culo anterior de esta serie sobre los servicios de Google Drive en Android ya vimos c贸mo configurar un nuevo proyecto en la consola de desarrolladores a帽adiendo la API de Drive para Android, y c贸mo realizar en nuestra aplicaci贸n las operaciones b谩sicas de creaci贸n y eliminaci贸n de ficheros y carpetas.

En este segundo art铆culo vamos a seguir profundizando en las funcionalidades que proporciona este servicio, y empezaremos por c贸mo consultar y modificar los metadatos de un fichero o carpeta ya existente.

La consulta de los metadatos de un fichero o carpeta seguir谩 una vez m谩s el mismo esquema que las operaciones que ya conocemos. En primer lugar llamaremos al m茅todo getMetadata() sobre el objeto DriveFile o DriveFolder que queramos consultar. Asignaremos un callback (ResultCallback) e implementaremos su m茅todo onResult() para ser notificado cuando finalice la operaci贸n. Si el resultado es correcto (getStatus().isSuccess())聽 podremos obtener los metadatos mediante el m茅todo getMetadata() del objeto MetadataResult recibido como par谩metro, y a partir de 茅ste cualquier dato concreto que necesitemos, por ejemplo su nombre (con getTitle()) o su fecha de 煤ltima actualizaci贸n (con getModifiedDate()). Pod茅is consultar el listado completo de m茅todos disponibles para recuperar cada metadato en la documentaci贸n de la clase MetadataResult.

Veamos c贸mo quedar铆a un m茅todo que recupere los metadatos de un fichero a partir de su DriveId:

private void getMetadata(DriveId fileDriveId) {
    DriveFile file = fileDriveId.asDriveFile();

    file.getMetadata(apiClient).setResultCallback(
        new ResultCallback<DriveResource.MetadataResult>() {
            @Override
            public void onResult(DriveResource.MetadataResult metadataResult) {
                if (metadataResult.getStatus().isSuccess()) {
                    Metadata metadata = metadataResult.getMetadata();
                    Log.i(LOGTAG, "Metadatos obtenidos correctamente." +
                            " Title: " + metadata.getTitle() +
                            " LastUpdated: " + metadata.getModifiedDate());
                }
                else {
                    Log.e(LOGTAG, "Error al obtener metadatos");
                }
            }
        });
}

Modificar los metadatos de un fichero/carpeta es tan sencillo como consultarlos. Crearemos en primer lugar un objeto MetadataChangeSet con los cambios que queramos realizar en los metadatos, igual que hac铆amos para crear un fichero nuevo. Una vez definidos los metadatos que queremos actualizar, llamaremos al m茅todo updateMetadata() pas谩ndole como par谩metros el conjunto de metadatos creados, asignaremos el callback habitual y revisaremos dentro del m茅todo onResult() que la operaci贸n ha finalizado correctamente.

Un m茅todo que actualizar谩 por ejemplo el t铆tulo de un fichero a partir de su DriveId quedar铆a de la siguiente forma:

private void updateMetadata(DriveId fileDriveId) {
    DriveFile file = fileDriveId.asDriveFile();

    MetadataChangeSet changeSet =
        new MetadataChangeSet.Builder()
            .setTitle("TituloModificado.txt")
            .build();

    file.updateMetadata(apiClient, changeSet).setResultCallback(
        new ResultCallback<DriveResource.MetadataResult>() {
            @Override
            public void onResult(DriveResource.MetadataResult metadataResult) {
                if (metadataResult.getStatus().isSuccess()) {
                    Metadata metadata = metadataResult.getMetadata();
                    Log.i(LOGTAG, "Metadatos actualizados correctamente.");
                }
                else {
                    Log.e(LOGTAG, "Error al actualizar metadatos");
                }
            }
        });
}

Al igual que podemos consultar y modificar los metadatos tambi茅n podremos, por supuesto, consultar y modificar el contenido de un fichero ya existente.

Tanto para leer como para escribir un fichero de Google Drive tendremos primero que abrirlo, indicando el modo de apertura correspondiente (apertura para leer o para escribir). Tras la apertura del fichero podremos acceder a su contenido (recordemos, objeto DriveContents), a partir del cual obtendremos su stream en entrada o salida asociado, sobre el que podremos utilizar la API est谩ndar de Java para la lectura/escritura de ficheros.

Detallemos en primer lugar el proceso de lectura de un fichero. Comenzaremos llamando al m茅todo open() sobre el fichero (DriveFile). Como par谩metro del m茅todo open() pasaremos el modo de acceso de lectura (DriveFile.MODE_READ_ONLY). Asignaremos el callback correspondiente y en el m茅todo onResult(), tras comprobar que la operaci贸n de apertura se ha realizado correctamente, llamaremos a getDriveContents() sobre el resultado recibido para obtener una referencia al contenido del fichero. Tras esto construiremos un objeto BufferedReader (api estandar java.io) a partir del stream de entrada asociado al contenido, que obtenemos llamando a getInputStream(). En mi caso de ejemplo acceder茅 a ficheros de texto, por lo que podemos leer el contenido linea a linea utilizando el m茅todo readLine(). Por 煤ltimo, llamamos al m茅todo discard() del objeto DriveContents para cerrar todos los recursos abiertos.

Se muestra a continuaci贸n el c贸digo completo de un m茅todo de lectura de ficheros de texto almacenados en Drive a partir de su DriveId:

private void readFile(DriveId fileDriveId) {

    DriveFile file = fileDriveId.asDriveFile();

    file.open(apiClient, DriveFile.MODE_READ_ONLY, null)
        .setResultCallback(new ResultCallback<DriveApi.DriveContentsResult>() {
            @Override
            public void onResult(DriveApi.DriveContentsResult result) {
                if (!result.getStatus().isSuccess()) {
                    Log.e(LOGTAG,"Error al abrir fichero (readFile)");
                    return;
                }

                DriveContents contents = result.getDriveContents();

                BufferedReader reader =
                    new BufferedReader(
                        new InputStreamReader(contents.getInputStream()));

                StringBuilder builder = new StringBuilder();

                try {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        builder.append(line);
                    }
                } catch (IOException e) {
                    Log.e(LOGTAG,"Error al leer fichero");
                }

                contents.discard(apiClient);

                Log.i(LOGTAG, "Fichero leido: " + builder.toString());
            }
       });
}

La escritura sobre un fichero ya existente es pr谩cticamente an谩loga. Comenzamos nuevamente abriendo el fichero llamando al m茅todo open() pas谩ndole esta vez el modo de acceso de escritura DriveFile.MODE_WRITE_ONLY. En el onResult() del callback asignado obtenemos una referencia al contenido del fichero mediante getDriveContents() y creamos un objeto BufferedWriter a partir de su stream de salida asociado, que obtenemos mediante getOutputStream(). Escribimos el texto deseado al fichero (insisto, en mi caso de ejemplo es texto, pero podr铆a ser cualquier contenido), y por 煤ltimo llamamos al m茅todo commit() sobre el objeto DriveContents para confirmar los cambios realizados. Sobre el m茅todo commit() tambi茅n podemos asignar un nuevo callback para verificar que se realiza correctamente. Tambi茅n indicar que opcionalmente, junto con el cambio de contenido del fichero, tambi茅n podremos actualizar los metadatos del mismo definiendo previamente un objeto MetadadataChangeSet y pas谩ndoselo como parametro al m茅todo commit(). Veamos un ejemplo completo que actualiza el contenido de un fichero almacenado en Google Drive a partir de su DriveId:

private void writeFile(DriveId fileDriveId) {

    DriveFile file = fileDriveId.asDriveFile();

    file.open(apiClient, DriveFile.MODE_WRITE_ONLY, null)
        .setResultCallback(new ResultCallback<DriveApi.DriveContentsResult>() {
            @Override
            public void onResult(DriveApi.DriveContentsResult result) {
                if (!result.getStatus().isSuccess()) {
                    Log.e(LOGTAG,"Error al abrir fichero (writeFile)");
                    return;
                }

                DriveContents contents = result.getDriveContents();

                BufferedWriter writer =
                    new BufferedWriter(
                        new OutputStreamWriter(contents.getOutputStream()));

                try {
                    writer.write("Contenido del fichero modificado!");
                    writer.flush();
                } catch (IOException e) {
                    Log.e(LOGTAG,"Error al escribir fichero");
                }

                //Opcional: cambio de metadatos
                MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
                     .setMimeType("text/plain")
                     .build();

                contents.commit(apiClient, changeSet).setResultCallback(
                    new ResultCallback<Status>() {
                        @Override
                        public void onResult(Status result) {
                            if(result.getStatus().isSuccess())
                                Log.i(LOGTAG, "Fichero escrito correctamente");
                            else
                                Log.e(LOGTAG, "Error al escribir fichero");
                        }
                    });
            }
        });
}

Por 煤ltimo vamos comentar una alternativa a la hora de abrir ficheros de Drive. Al igual que ocurre para crear ficheros, la API聽de Google Drive para Android tambi茅n nos ofrece una actividad predefinida para poder seleccionar un fichero de la cuenta de Google Drive del usuario logueado. Esta actividad permitir谩 al usuario seleccionar un fichero de su cuenta y nos devolver谩 como resultado, entre otras cosas, su DriveId asociado. Con este DriveId podremos leer o escribir el contenido del fichero con cualquiera de los dos m茅todos implementados anteriormente. Veamos c贸mo hacerlo.

De forma an谩loga a la actividad de creaci贸n de ficheros, lo primero que haremos ser谩 el IntentSender con el que lanzaremos la actividad. Utilizaremos para ello el m茅todo newOpenFileActivityBuilder() de la API de Drive. Tenemos la posibilidad de filtrar los ficheros que se mostrar谩n al usuario por su tipo de contenido (MIME Type) mediante el m茅todo setMimeType() del builder, que recibi un array con los tipos visualizables. As铆, si por ejemplo queremos que s贸lo se puedan seleccionar fichero de texto plano podemos llamar a setMimeType(new String[] { 芦text/plain禄 }). Tambi茅n podemos personalizar el t铆tulo de la actividad mostrada mediante setActivityTitle() o la carpeta inicial mediante setActivityStartFolder().

Construido el IntentSender lanzamos la actividad llamando a startIntentSenderForResult() pas谩ndole como par谩metro una constante arbitraria identificativa de la operaci贸n, en mi caso llamada REQ_OPEN_FILE. El resultado de esta acci贸n lo recibiremos en el m茅todo onActivityResult() de la actividad principal y lo identificaremos por su constante identificativa. Dentro de dicho m茅todo podremos obtener el DriveId del fichero seleccionado accediento al extra del intent recibido como par谩metro con el identificador OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID. Una vez obtenido el DriveId del fichero podremos por ejemplo leer su contenido llamando a nuestro m茅todo auxiliar readFile() que ya describimos anteriormente:

private void openFileWithActivity() {

    IntentSender intentSender = Drive.DriveApi
        .newOpenFileActivityBuilder()
        .setMimeType(new String[] { "text/plain" })
        .build(apiClient);

    try {
        startIntentSenderForResult(
            intentSender, REQ_OPEN_FILE, null, 0, 0, 0);
    } catch (IntentSender.SendIntentException e) {
        Log.e(LOGTAG, "Error al iniciar actividad: Open File", e);
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        //...
        case REQ_OPEN_FILE:
            if (resultCode == RESULT_OK) {
                DriveId driveId = data.getParcelableExtra(
                    OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);

                Log.i(LOGTAG, "Fichero seleccionado ID = " + driveId);

                readFile(driveId);
            }
            break;
        default:
            super.onActivityResult(requestCode, resultCode, data);
            break;
    }
}

Si ejecutamos la aplicaci贸n de ejemplo y lanzamos el m茅todo anterior podremos ver c贸mo la aplicaci贸n nos muestra la actividad siguiente de selecci贸n de ficheros:

open-file-activity

Y con esto terminar铆amos con el apartado de operaciones de lectura y escritura de metadatos y contenido de ficheros almacenados en Drive desde Android.

Puedes consultar y/o descargar el c贸digo completo de los ejemplos desarrollados en este art铆culo accediendo a la p谩gina del curso en GitHub.

[mensaje-curso]

Tambi茅n te puede interesar

5 comentarios

Google Drive en Android [Serie] | sgoliver.net 29/09/2016 - 16:16

[…] Google Drive en Android (2)聽[Act. Septiembre 2016] […]

Responder
Pedro Sanchez Rodriguez 21/11/2016 - 0:06

Hola. Para trabajar con archivos sqlite (.db) deberia utilizar los metodos descritos o hay algunos especificos? Tengo creada una aplicacion con la API de android para sqlite, (es una peque帽a app )pero quisiera guardar la .db en DRIVE en lugar de la memoria interna del terminal. Gracias

Responder
Abraham Parima 12/01/2017 - 17:18

Es posible crear un Socket con los ficheros de google drive.

Responder
Abraham Parima 12/01/2017 - 17:22

Existe alguna manera de poder abrir el contenido de un fichero que se encuentra en la nube desde un archivo com煤n desde la clase java.nio.file otra. Gracias

Responder
1 01/06/2017 - 10:04

Hello,
I should like to download a Zip file but 禄 reader.readLine()禄 only accept text files. How can I do to achieve ?
Thanks a lot.
Fabrice

Responder

Dejar un comentario

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si contin煤a navegando est谩 dando su consentimiento para la aceptaci贸n de las mencionadas cookies y la aceptaci贸n de nuestra pol铆tica de cookies, pinche el enlace para mayor informaci贸n. Aceptar M谩s Informaci贸n

Pol铆tica de Privacidad y Cookies