Android: Guión para crear tu propia aplicación - AppQuiz

Rafa Morales 9 Octubre 2018
20min
0
Preguntas

Os proponemos aprender a programar en Android creando vuestra propia aplicación. Se trata de un guión donde te diremos qué debes hacer y dónde puedes encontrar la documentación que te ayude a realizarlo. Cuando no indico nada de documentación es porque ya se ha realizado en apartados anteriores y deberías saber hacerlo. Espero que os sea de ayuda.

 

Objetivos del proyecto "AppQuiz"

Realizaremos una aplicación que nos permita crear un banco de preguntas tipo test en nuestro dispositivo móvil y realizar cuestionarios aleatorios con dichas preguntas para estudiar de cara a posibles exámenes.

Un pequeño boceto sobre la navegación entre pantallas que tendrá que seguir nuestra aplicación se puede consultar en el siguiente enlace:

 

Conociendo Android Studio y creando "Hola mundo"

Para el desarrollo de aplicaciones Android, Google nos ofrece un Entorno de Desarrollo preparado con todas las herramientas necesarias para facilitar nuestro trabajo. Realizaremos los siguientes pasos para ir conociéndo Android Studio y crear nuestra primera aplicación (Documentación para todos los puntos).

  • Cómo instalar Android Studio y qué instalar del SDK .
  • Cuál es la estructura básica de un proyecto en Android Studio.
  • Cuáles son los componentes básicos de una aplicación Android.
  • Desarrollar una aplicación de ejemplo Android, "Hola Mundo".
  • Conocer el emulador nativo de Android Studio.
  • Conocer emuladores alternativos externos a Android Studio.
  • Cómo utilizar mi propio móvil para probar mi aplicación.

 

Comenzando el proyecto "APPquiz" y diseñando la pantalla de logo

Comienza tu proyecto creando una nueva aplicación que funcione en versiones de Android 4.4 (API-19) o superiores. Dedícale un rato a pensar un nombre y un logo que la identifique. En Internet encontrarás multitud de recursos libres de uso que podrás añadir a tu proyecto (Documentación).

También debemos conocer los estilos y colores, así como las unidades de medida que se utilizan en los dispositivos (Documentación).

Como muchas aplicaciones del mercado, vamos a hacer que la primera pantalla que de nuestra aplicación muestre el logo y el nombre de nuestra aplicación. Nuestro proyecto debe incluir recursos de imágenes, cadenas, etc. Debemos aprender a incluirlos y a utilizarlos (Documentación). Para realizar un buen diseño de su interfaz debes conocer los fundamentos de Material Design (Documentación).

La pantalla de logo no debe mostrar el Toolbar, por lo que si has utilizado una actividad que la incluye debes eliminarla o utilizar un tema que no la incluya (Documentación). Puede que tengas que modificar el archivo AndroidManifest.xml, así que familiarízate con su contenido y para qué sirve (Documentación).

Utiliza un clase para almacenar todas los valores constantes de tu aplicación y así poder modificarlos más rápidamente (Documentación).

 

El log de la aplicación y su depuración

Tanto las aplicaciones como el propio sistema Android permiten mostrar mensajes de Log para informar de sus actividad o de posibles errores. Conoce qué niveles de Log existe, cómo acceder al log desde Android Studio y cómo crear mensajes de Log en tu aplicación (Documentación).

Crea tu propia clase "MyLog" y utilízala en tu código en lugar de "Log". En todas tus actividades y fragmentos, sobreescribe siempre los métodos que definen el ciclo de vida del mismo y envía un mensaje de log cuando se inicie. De esta manera podrás conocer en cada momento qué metodos se han ejecutado y te ayudará a comprender mejor su funcionamiento (Documentación).

Android Studio trae implementada la opción para depurar paso a paso la aplicación que desarrolles, una función muy útil para comprender su ejecución y subsanar errores (Documentación).

Acostúmbrate a comentar el código fuente de tu aplicación.

 

Diseñando una aplicación multilenguaje

Anteriormente hemos utilizado el recurso "string" para representar cadenas en la aplicación, podemos ampliar su funcionamiento traduciendo estas cadenas a diferentes idiomas para hacer que nuestra aplicación tenga funcionalidad de multilenguaje. Recuerda utilizar los plurales necesarios. Cambiando el idioma de nuestro dispositivo se cambiará automáticamente el idioma de nuestra aplicación (Documentación).

 

Iniciando la pantalla resumen de calificaciones

Crearemos una actividad básica (que incluye un botón flotante y una barra de herramientas) para mostrar un resumen con el número de categorías y preguntas que tenemos almacenadas y la calificación media de los cuestionarios que hemos realizado. Prepara los TextView que necesites para estos valores, por ejemplo los que se nombran a continuación (Documentación).

  • Preguntas disponibles: 10
  • Categorías disponibles: 2
  • Cuestionarios realizados: 10
  • Calificación media: 6.7/10

A esta actividad se accederá automáticamente tras mostrarse durante unos segundos la actividad del logo (Documentación).

Analizaremos el Ciclo de Vida de una Actividad. Incluiremos en el código Java de la actividad los métodos de cada estado de la Actividad, y en cada uno de ellos enviaremos mensajes al Log para comprobar que se ha entrado en ese estado (Documentación).

Según vamos mostrando actividades en nuestra aplicación, éstas se van mostrando encima de las anteriores, pero también podemos matarlas para que desaparezcan de la misma. Debemos conocer el funcionamiento de la pila de actividades en una aplicación para manejar correctamente las actividades (Documentación).

Las actividades deben controlar los botones "Up" y "Back" para navegar entre ellas. En nuestro caso vamos a matar la actividad del logo, por lo que al pulsar el botón "Back" de nuestra aplicación saldremos de la misma, al no existir más actividades. Y como es la primera actividad, el botón "Up" tampoco debe aparecer (Documentación).

 

Definiendo la pantalla AcercaDe

Las aplicaciones suelen tener una pantalla en la que se muestra la información del creador y/o desarrollador de la misma, licencias y toda la información que creas necesaria. Crearemos una actividad para mostrar la información del desarrollador de la aplicación y definiremos sus botones "Up" y "Back".

Modificaremos el "Toolbar" de la pantalla resumen de calificaciones para incluir en el menú una opción que abra esta actividad (Documentación).

 

Iniciando la pantalla listado de preguntas

Crearemos una actividad básica (que incluye un botón flotante y una barra de herramientas) para mostrar un listado de las preguntas que tenemos almacenadas en el dispositivo, aunque ahora mismo en ella sólo mostraremos un "TextView" que indique "Aún no has añadido ninguna pregunta".

A esta actividad accederemos desde una opción dentro del menú del "Toolbar" de la pantalla resumen de calificaciones.

 

Iniciando la pantalla crear/editar pregunta

Al pulsar el botón flotante de la pantalla listado de preguntas, accederemos a una nueva pantalla donde crearemos una nueva pregunta. La cual necesitará los siguientes datos:

  • Enunciado de la pregunta (TextEdit).
  • Categoría de la pregunta (Spinner): En un principio la lista de categorías se rellenará directamente desde Java.
  • Respuesta correcta (TextEdit).
  • Respuesta incorrecta 1 (TextEdit).
  • Respuesta incorrecta 2 (TextEdit).
  • Respuesta incorrecta 3 (TextEdit).
  • Guardar pregunta (Button).

Tras pulsar el "Button", el primer paso es comprobar si se han rellenado todos los campos, en caso contrario se mostrará una notificación del tipo "SnackBar" para indicárselo al usuario (Documentación).

En el momento de pulsar el "Button" tendremos que ocultar el teclado por si mostramos una notificación (Documentación).

Si se han rellenado todos los campos, crearemos un objeto "Pregunta" con los datos de dicha pregunta.

EXTRA (1):

Indicar en el "SnackBar" qué campos contienen errores o sombrear esos campos con otro color.

 

Almacenando la pregunta en una base de datos local

Para manejar la base de datos utilizaremos una clase que implemente el Modelo (dentro del patrón MVC - Modelo Vista Controlador) denominada "PreguntasRepositorio", que será la encargada de manejar el acceso a los datos y, por tanto, contendrá los métodos insertar, actualizar, eliminar y consultar (que serán públicos y estáticos). Estos métodos trabajarán con objetos "Pregunta" y con el contexto de la "Activity" necesario para el acceso a la base de datos SQLite.

Debemos crear la base de datos local (con los tipos de datos que permite SQLite), pero podemos modificar el directorio por defecto donde se almacena la base de datos mientras se desarrolla la aplicación para poder analizarla con otras aplicaciones (Documentación).

A continuación insertamos en la base de datos los datos de la pregunta (Documentación).

En el caso de cualquier error con la base de datos se le notificará al usuario mediante un "SnackBar".

 

Actualizando la pantalla del listado de preguntas

Si la pregunta se ha almacenado correctamente, finalizaremos la pantalla crear/editar pregunta y volveremos a la pantalla del listado de preguntas.

Leeremos de la base de datos todas las preguntas y las almacenaremos en un "ArrayList" (Documentación).

A continuación creamos un "Adapter" (adaptador) a partir del "ArrayList" que nos servirá para mostrarlo en la actividad dentro de un "RecyclerView ", bajo el "TextView" que ya teníamos y debemos ocultar en el momento que tengamos al menos una pregunta en la lista. Cada elemento del "RecyclerView" debe mostrar el enunciado de la pregunta y su categoría. Debemos realizar este paso en el método "onResume" para que se actualice el contenido del "RecyclerView" cada vez que volvamos a cargar la actividad (Documentación).

EXTRA:

Si el enunciado de la pregunta es demasiado largo, se puede fijar una longitud máxima para truncar la cadena y añadirle puntos suspensivos.

 

Editando una pregunta almacenada

Al pulsar una pregunta de la lista, iniciaremos de nuevo la pantalla de crear/editar pregunta y le enviaremos el identificador de la pregunta que se ha pulsado. Se leerá de la base de datos la información de dicha pregunta y se cargarán sus valores en el formulario para que el usuario pueda editarlos.

Al pulsar el "Button", debemos saber que estamos actualizando una pregunta, y no creando una nueva, para así hacer una actualización de dicha pregunta en la base de datos (Documentación).

En el caso de cualquier error con la base de datos se le notificará al usuario mediante un "SnackBar".

Si la pregunta se ha almacenado correctamente, finalizaremos la pantalla crear/editar pregunta y volveremos a la pantalla del listado de preguntas.

 

Mejorando la pantalla crear/editar pregunta

Vamos a definir correctamente el "Spinner" de las categorías rellenando las diferentes opciones a partir de las categorías almacenadas en la base de datos SQLite. Por tanto, tendremos que realizar una consulta que sólo nos muestre las categorías sin repetir y en orden alfabético. Cuando no hay preguntas almacenadas en la base de datos, no habrá ninguna categoría para elegir en el "Spinner", así que crea una que indique al usuario que pulse el botón para añadir una categoría nueva.

A continuación vamos a definir junto al "Spinner" un nuevo botón que nos permita añadir nuevas opciones al "Spinner" mediante un "AlertDialog" que pida al usuario el texto de la categoría y seleccione automáticamente esa nueva opción (Documentación).

 

Eliminando una pregunta almacenada

Dentro de la pantalla Crear/Editar pregunta, debemos añadir un nuevo "Button" que nos permita eliminar dicha pregunta a través de "AlertDialog" que nos pregunte si estamos seguros de querer eliminarla (Documentación).

EXTRA:

Definir un gesto swipe en el listado de preguntas para eliminarla también con un "AlertDialog".

 

Actualizando la pantalla resumen de calificaciones

Incluir nuevos métodos en el modelo "PreguntasRepositorio" para actualizar los datos de la pantalla resumen de calificaciones cada vez que se muestre dicha pantalla, por lo que deberíamos hacerlo en el método "onResumen".

 

Añadiendo imágenes a la pantalla crear/editar pregunta y comprobando los permisos

Vamos a añadir un "Button" que nos permita capturar una imagen desde la cámara fotográfica del dispositivo y otro "Button" que nos permita elegir una imagen desde la galería fotográfica del dispositivo. Al pulsar cualquiera de los dos botones, como lo que vamos a hacer es trabar con imágenes almacenadas en el memoria externa del dispositivo, lo que vamos a hacer es comprobar si el usuario tiene los permisos necesarios para escribir en la memoria externa. Si la aplicación se ejecuta en la versión Marshmallow o superior, al ser un permiso peligroso, hay que pedirle al usuario que acepte o rechace dicho permiso en tiempo de ejecución. Si la aplicación se ejecuta en una versión inferior, sólo realizaremos la comprobación. En ambos casos, si no se tuviera ese permiso, se mostraría un "SnackBar" al usuario para informarle de ello. Hay que tener en cuenta que la ventana de petición del permiso puede mostrarse tanto desde el botón de la cámara fotográfica como desde la galería, por lo que tendremos que tener dos casos diferentes en el método "onRequestPermissionsResult" (Documentación).

El "Button" que nos permita capturar una imagen desde la cámara fotográfica del dispositivo realizará el siguiente procedimiento. Una vez capturada la imagen, ésta se almacenará en el almacenamiento externo del dispositivo como imagen JPG. A continuación la aplicación leerá dicha imagen, reducirá su resolución (a 200 píxeles como máximo) y la mostrará en un "ImageView" en la pantalla (Documentación).

El "Button" que nos permita elegir una imagen desde la galería fotográfica del dispositivo realizará el siguiente procedimiento. Una vez elegida la imagen, reducirá su resolución (a 200 píxeles como máximo) y la mostrará en el mismo "ImageView" (Documentación).

Al pulsar el "Button" para guardar la pregunta, la imagen del "ImageView", si existe, se convertirá al formato de texto BASE64 y se almacenará en un campo nuevo de la base de datos de tipo cadena junto al resto de campos de la pregunta (Documentación).

Por último, cuando entremos a editar una pregunta, si dicha pregunta no tiene imagen, se debe mostrar dentro del "ImageView" una imagen  de fondo (background) por defecto que lo indique. Por el contrario, si dicha pregunta posee una imagen en la base de datos, se debe recuperar y cargar en el "ImageView".

Vamos a terminar añadiendo un tercer "Button" que al pulsarlo elimine el contenido del "ImageView" (Documentación).

 

Exportando preguntas en fichero adjunto a una correo electrónico

En la pantalla del listado de preguntas añadir una opción más al menú que nos permita exportar todas las preguntas con el siguiente procedimiento.

Crea un fichero de texto en formato XML que almacene todas las preguntas almacenadas en la base de datos. La sintaxis del documento XML deberá ser igual a la de este archivo, que es una versión reducida del formato de preguntas XML de Moodle. Este fichero se almacenará en el almacenamiento externo de la aplicación, por lo que habrá que volver a comprobar los permisos de escritura. El proceso de devolver una cadena de texto con el contenido en XML se deberá realizar dentro del Modelo "PreguntasRepositorio" que tenemos creado (Documentación).

A continuación se incluirá como adjunto este fichero en un correo electrónico que pueda ser enviado desde cualquier aplicación del móvil a la dirección que el usuario elija. Este proceso se realizará mediante un "Intent implícito" que pregunte al usuario qué aplicación de correos electrónicos del dispositivo quiere utilizar (Documentación).

 

Importando preguntas desde otra aplicación

Prepararemos nuestra aplicación para que permita recibir ficheros de texto en formato XML desde cualquier otra aplicación del dispositivo mediante un "Intent-filter" (Documentación). Al recibir el fichero se abrirá directamente la pantalla resumen de calificaciones, leerá el contenido del archivo, analizará el contenido (cuya sintaxis XML debe ser idéntica a la comentada anteriormente) e insertará en la base de datos local todas las preguntas. Al finalizar el proceso, indicará en la misma pantalla mediante un "TextView", cuántas preguntas nuevas se han insertado o si ha ocurrido algún error. El procedimiento de leer una cadena de texto con el contenido del XML y de insertar las preguntas se deberá incluir dentro del Modelo "PreguntasRepositorio" que tenemos creado (Documentación).

 

Añadiendo opciones de configuración

Gracias a "PreferenceActivity" podemos dotar a la aplicación de una pantalla de opciones de configuración que se almacenan de manera automática sin nosotros tener que preocuparnos por su implementación (Documentación). Le vamos a añadir a la aplicación las siguiente opciones:

  • Cambiar el lenguaje de la aplicación entre español e inglés. En el método "onResume" de cada actividad modificaremos el lenguaje de la aplicación (Documentación).
  • Introducir una dirección URL desde la que poder descargarnos un fichero XML con preguntas.

 

Importando preguntas desde un servidor remoto

En la pantalla del listado de preguntas añadir una opción más al menú que nos permita importar preguntas desde un servidor remoto con el siguiente procedimiento.

Comenzaremos comprobando los permisos de Internet, de acceso al estado de la red y al estado del wifi. Si la aplicación no tuviera alguno de esos permisos se mostraría un "SnackBar" al usuario para informarle de ello, ya que son permisos que no se pueden pedir al usuario, pero que hay que comprobarlos por si acaso (Documentación).

Si tenemos los permisos anteriores, comprobaremos que tenemos o la red o el wifi activos. Si ninguno de los dos estuviera activo se mostraría un "SnackBar" al usuario para informarle de ello. Se puede incluir un enlace a la configuración de red del dispositivo y que el usuario pueda habilitarlo (Documentación).

Si todas las comprobaciones anteriores son correctas, lanzaremos la conexión a un recurso de Internet. Android nos obliga a realizar una "AsyncTask" (tarea asíncrona) para ello y que de esa manera el usuario pueda seguir trabajando con la aplicación. A la "AsyncTask" le pasaremos como parámetro la URL que el usuario ha introducido en opciones (Documentación).

Una vez dentro de la tarea asíncrona realizaremos la conexión al servidor remoto, obteniendo el contenido de la respuesta (Documentación).

En el caso de que no se pueda realizar la conexión al servidor remoto se le notificará al usuario mediante un "SnackBar". La "AsyncTask" debe recibir también como parámetro el contexto de la actividad para poder mostrar la notificación.

Mientras se realiza la "AsyncTask" mostraremos una "ProgressBar" para que el usuario sepa que se está realizando el proceso en segundo plano (Documentación).

Si se ha realizado correctamente la conexión y nos hemos descargado los datos del servidor, debemos importarlos mediante el método del Repositorio que habíamos realizado anteriormente. El resultado de la importación, tanto correcta como incorrecta se mostrará en un "SnackBar" en la misma actividad.

 

Escuchando los broadcasts del sistema

Preparamos nuestra actividad para recibir los "Broadcasts" de cambios en el estado de la red de datos y Wifi. Cuando se deshabiliten datos y WiFi se debe mostrar un "Toast" indicándolo. El BroadcastReceiver debe programarse dinámicamente sólo en la pantalla del listado de acontecimientos. (Documentación).

 

Insertando animaciones

Crea una pequeña animación en cualquier parte de la aplicación, utilizando las clases propias del SDK de Android.