Vistas de la base de datos con Room para Android

Room es una capa de abstracción sobre SQLite que Google empaquetó como una biblioteca de AndroidX y también recomienda. Desde la versión 2.1, Room ofrece la posibilidad de añadir Vistas de Base de Datos, también conocidas como consultas almacenadas.

Algunas de las buenas razones para utilizar Vistas de Base de Datos serían:

  • Le facilitan la escritura de consultas complejas y su uso en consultas de Objetos de Acceso a Datos (DAO).
  • Puedes consultar sólo los campos que necesitas, en lugar de tener que recorrer todos los campos de una tabla.

En este tutorial, construirás una aplicación de Encuestas a Clientes que permite a los clientes de un restaurante dejar sus comentarios, y luego guarda esos comentarios en la base de datos administrada por Room. Durante el proceso aprenderás lo siguiente:

  • ¿Qué es una Vista de Base de Datos?
  • ¿Cómo crear Vistas de Base de Datos?
  • Cómo usarlas para simplificar la escritura de consultas SELECT
Nota: Este tutorial asume que tienes experiencia en el desarrollo para Android en Kotlin y que has trabajado con Room antes. Si no estás familiarizado con Room, echa un vistazo a nuestro tutorial Persistencia de datos con Room.

Este tutorial también utiliza Coroutines con Room. Para saber más, lea nuestro tutorial Coroutines With Room Persistence Library.

Cómo empezar

Descargue el proyecto de inicio haciendo clic en el botón Download Materials en la parte superior o inferior de este tutorial.

Extraiga el archivo ZIP y abra el proyecto de inicio en Android Studio 4.0 o posterior seleccionando Open an existing Android Studio project en la pantalla de bienvenida.

Una vez completada la sincronización con Gradle, explora la estructura del proyecto. El proyecto sigue la arquitectura MVVM, por lo que las funcionalidades similares están bajo un mismo paquete. Familiarízate con los paquetes presentes – los usarás en este tutorial.

Construye y ejecuta. Verá una pantalla sencilla con un mensaje de bienvenida, una imagen y un botón START SURVEY.

Pantalla de Inicio de Encuesta de la app de Encuestas a Clientes

Toque el botón de INICIO DE ENCUESTA. Para el propósito de este tutorial, puede ignorar el hecho de que no ha comido en el restaurante. :]

La siguiente pantalla es la de la encuesta. Tiene un campo de entrada de correo electrónico, botones de radio para elegir la comida que está calificando y tres preguntas. Cada pregunta tiene botones de «bueno», «medio» y «malo» debajo, para que el usuario pueda calificar su satisfacción.

Pantalla de la encuesta de la aplicación Customer Surveys con preguntas y posibles calificaciones

También verás el botón SUBMIT SURVEY. Tócalo y verás un brindis que dice que aún no es hora de hacer la encuesta. No te preocupes, lo solucionarás a lo largo de este tutorial.

Ahora te han dado la bienvenida al restaurante The View, donde podrás ver increíbles vistas de la naturaleza, probar sus deliciosos platos y valorar tu satisfacción. Mientras que en él, usted también aprenderá acerca de las vistas de la base de datos de habitaciones.

Usando las vistas de la base de datos

Considera una tabla que tiene una funcionalidad extra de consultas SELECT pre-empacadas para la conveniencia. La versión 2.1 y superior de Room las denomina Vista de base de datos y proporciona una anotación con el mismo nombre, es decir, @DatabaseView.

Usando esta anotación puedes marcar una clase para que se comporte como una Vista de Base de Datos. Esto le permitirá adjuntar una consulta a la clase, como a continuación:

@DatabaseView("SELECT user.id, user.name " + "AS departmentName FROM user " + "WHERE user.departmentId = department.id")class User { var id: Long = 0 var name: String? = null}

A continuación, puede utilizar esta clase en su DAO para consultar los datos de la misma manera que lo haría con una clase marcada como una Entidad, es decir, Tabla en una base de datos.

Un DAO le ayuda a acceder a los datos de la base de datos de su aplicación. Normalmente contiene los métodos CUD (Create, Update y Delete) y también puede contener otros métodos que pueden ser necesarios para el acceso de lectura y escritura a la base de datos.

La relación entre las Vistas de Base de Datos y la base de datos es similar a la relación entre las entidades y la base de datos. A continuación se profundizará en esas relaciones.

Comparación de una Vista de Base de Datos y una Entidad

Las clases anotadas con @DatabaseView son similares a las clases Entity. He aquí cómo:

  • Ambos pueden utilizar SELECT FROM en las consultas DAO.
  • Database Views y Entitys pueden ambos utilizar @ColumnInfo, que permite personalizar la información de la columna asociada a un campo.
  • Ambos pueden utilizar @Embedded, que permite que un campo tenga campos anidados que las consultas pueden referenciar directamente.

Aunque hay muchas similitudes entre los dos, también hay diferencias entre DatabaseViews y Entitys:

  • Se puede utilizar INSERT, UPDATE y DELETE con un Entity, pero no con un DatabaseView.
  • Defines todas tus vistas en tus apps usando views, pero defines las entidades usando entities.

Ahora que sabes qué es un DatabaseView y cómo se compara y contrasta con una clase Entity, es el momento de usarlo y empezar a presentar la encuesta para El Restaurante de Vistas.

Enviar la encuesta

Tu primer paso es añadir la lógica para enviar la encuesta y guardarla en la base de datos de Room después de tocar el botón SUBMIT SURVEY.

Navega hasta customersurveys/CustomerSurveyFragment.kt, donde añadirás la lógica para recoger las respuestas y guardarlas en Room. Hazlo reemplazando el código en submitSurvey() con esto:

// 1val email = editEmail.text.toString()// 2if (validateEmail(email)) { // 3 val meal = when (radioGroupMeals.checkedRadioButtonId) { R.id.radioBreakfast -> "Breakfast" R.id.radioLunch -> "Lunch" R.id.radioDinner -> "Dinner" else -> "No Meal" } // 4 val customerSurvey = SurveyListItem .CustomerSurvey(0, email, meal, questionOneAnswer, questionTwoAnswer, questionThreeAnswer) customerSurveyViewModel.insertCustomerSurvey(customerSurvey) // 5 findNavController() .navigate(R.id.action_surveyFragment_to_surveyCompletedFragment)}

Esto es lo que estás haciendo con este código:

  1. Obtienes el correo electrónico de editEmail y lo asignas a una variable: email.
  2. Esta comprobación de la condición llama a validateEmail(email), que comprueba si el correo electrónico es null o no. Devuelve false si es null. También comprueba si el correo electrónico introducido es válido y devuelve false si no lo es.
  3. El código dentro de la sentencia if se ejecuta cuando validateEmail(email) devuelve true. meal mantiene el tipo de comida que el usuario seleccionó de los grupos de radio.
  4. Una vez que tiene el valor de meal, crea SurveyListItem.CustomerSurvey, que tiene toda la información sobre la encuesta. Saca los valores de questionOneAnswer, questionTwoAnswer y questionThreeAnswer de toggleButtonListeners(), que tiene listeners para ello.
  5. Aquí se guarda customerSurvey llamando a insertCustomerSurvey(customerSurvey) en CustomerSurveyViewModel, que maneja la lógica para guardar en Room.
  6. Se navega a SurveyCompletedFragment.

Después de añadir esto, notará que customerSurveyViewModel y findNavController() tienen subrayados en rojo. Para arreglar esto, primero añada la inicialización CustomerSurveyViewModel en la parte superior de la clase, justo debajo de la inicialización questionThreeAnswer.

private val customerSurveyViewModel: CustomerSurveyViewModel by viewModels()

Asegúrese de añadir las respectivas declaraciones de importación cuando el IDE le pida.

Construya y ejecute. Inicie la encuesta, introduzca el correo electrónico requerido y seleccione sus respuestas a las preguntas.

Pantalla de la encuesta con las respuestas

Grandioso, ha completado la encuesta.

Ver todas las encuestas usando la vista de la base de datos Captura de pantalla

Toque el botón VER ENCUESTAS… oops, no hace nada todavía. No te preocupes, lo arreglarás pronto.

En la siguiente sección, aprenderás a crear tu primera DatabaseView.

Crear una vista de base de datos

Para crear una vista, añadirás una anotación @DatabaseView a una clase o clase de datos. Comience por navegar a customersurveys/SurveyListItem.kt. Esta es una clase sellada con un par de clases de datos para que usted utilice en este tutorial.

En la parte inferior de SurveyListItem, justo debajo de QuestionOneSadView, agregue lo siguiente:

data class HappyBreakFastView( override val email: String) : SurveyListItem()

Esta clase de datos anula la variable de correo electrónico de SurveyListItem y hereda de la clase – lo que significa que es un subtipo de SurveyListItem.

Después de crear esta clase de datos, añada @DatabaseView con una consulta SELECT para obtener todos los identificadores de correo electrónico de la tabla CustomerSurvey donde la comida se establece como «Desayuno», justo encima de la clase de datos HappyBreakFastView. Su anotación debería tener el siguiente aspecto:

@DatabaseView("SELECT CustomerSurvey.email FROM CustomerSurvey WHERE CustomerSurvey.meal = 'Breakfast'")

Algunas cosas a tener en cuenta sobre la consulta dentro de la anotación:

  • La consulta funciona como cualquier otra consulta que haya escrito en Room.
  • Necesita solicitar todos los campos que tenga en su clase de datos mientras escribe la consulta. En este caso, sólo necesitas el correo electrónico. Utiliza SELECT CustomerSurvey.email From... para obtener el correo electrónico de CustomerSurvey.
Nota: Para este tutorial, mantienes las vistas y la entidad dentro de SurveyListItem para evitar la repetición y para que el código sea más fácil de leer. No siempre tienes que subclasificar tus vistas en una clase sellada; también pueden estar en su propio archivo o clase separada.

¡Felicidades, has creado tu primera vista! A continuación, vas a ver cómo puedes utilizar la vista en tus consultas DAO.

Utilización de las vistas de la base de datos de la sala en las consultas DAO

Primero, incluirás HappyBreakFastView en views en el @Database de la app.

Navega hasta database/AppDatabase.kt y, dentro de views, añade SurveyListItem.HappyBreakFastView::class. Su anotación @Database actualizada debería tener el siguiente aspecto:

@Database(entities = , version = 2, exportSchema = false, views = )

Nota que el version = 2. Debe actualizar la versión de la base de datos cada vez que añada un view en la AppDatabase – de lo contrario, su aplicación se bloqueará. En este caso, has actualizado la versión a 2. Sincroniza gradle para aplicar todos estos cambios.

A continuación, navega hasta customers/CustomerSurveysDao.kt y, justo debajo de getQuestionOneSadView(), añade el siguiente código:

@Query("SELECT * FROM HappyBreakFastView")fun getHappyBreakFastCustomers():LiveData<List<SurveyListItem.HappyBreakFastView>>

Este método obtiene todos los clientes que estaban contentos con cualquier aspecto de la encuesta del restaurante. Para explicarlo con más detalle:

  • Primero, se utiliza HappyBreakFastView como se haría en una consulta normal.
  • Se llama a este método en CustomerSurveyRepo para obtener una lista de todos los clientes que respondieron a alguna de las preguntas con Bien. Observa que el tipo de retorno del método es una lista LiveData de tipo SurveyListItem.HappyBreakFastView, que es un soporte de variable observable.

Ahora, has creado un view y el método para consultar la lista de clientes que respondieron con una respuesta positiva en CustomerSurveysDao. En la siguiente sección, usted aprenderá cómo llamar a este método de la clase de repositorio.

La obtención de datos utilizando un DatabaseView

Navegue a customersurveys/CustomerSurveyRepo.kt y añadir el siguiente método justo debajo de getQuestionOneSadView():

fun getHappyBreakFastCustomers() : LiveData<List<SurveyListItem.HappyBreakFastView>> { return customerSurveysDao.getHappyBreakFastCustomers()}

Este método llama getHappyBreakFastCustomers() de CustomerSurveysDao para obtener los datos de la Sala. Su tipo de retorno es un LiveData, lo que permite al que llama a este método observar cualquier cambio en los datos.

A continuación, se añade una llamada a getHappyBreakFastCustomers() en CustomerSurveyViewModel. Es responsable de mostrar los datos a la vista – que, en este caso, no es DatabaseView sino AllSurveysFragment.

Navega hasta customersurveys/CustomerSurveyViewModel.kt y añade el siguiente código:

val happyBreakfastCustomers : LiveData<List<SurveyListItem.HappyBreakFastView>> by lazy { customerSurveyRepo.getHappyBreakFastCustomers()}

Esta variable obtiene su valor llamando a getHappyBreakFastCustomers() desde CustomerSurveyRepo. Hay un by lazy{} para que no cargue los datos inmediatamente, sino cuando se accede a la variable por primera vez.

A continuación, actualizará la UI para que pueda mostrar los datos.

Mostrar los datos a la UI

Navegue a allsurveys/AllSurveysFragment.kt y añade el siguiente código en la parte inferior de la clase:

private fun getHappyBreakfastCustomers() { customerSurveyViewModel.happyBreakfastCustomers.observe(viewLifecycleOwner, Observer { customerSurveyList -> if (customerSurveyList.isEmpty()) { layoutEmptyView.visibility = View.VISIBLE rvReviews.visibility = View.GONE } else { layoutEmptyView.visibility = View.GONE rvReviews.visibility = View.VISIBLE initView(customerSurveyList) } })}private fun initView(customerSurveySurveyList: List<SurveyListItem.HappyBreakFastView>) { val customerSurveysAdapter = CustomerSurveysAdapter(customerSurveySurveyList) rvReviews.adapter = customerSurveysAdapter}

Para explicar lo que hace el código:

  • Primero, llama a happyBreakfastCustomers y observa su valor.
  • Dentro de la lambda observar, hay una comprobación para ver si customerSurveyList es null o no. Si la lista es null, se pone el mensaje de TextView¡No se han encontrado encuestas! como visible y se oculta RecyclerView. Si no es null, pones la visibilidad de TextView a GONE y muestras RecyclerView. También llamas a initView(customerSurveyList) con el valor customerSurveyList de CustomerSurveyViewModel.
  • initView(customerSurveySurveyList: List)Inicializa CustomerSurveysAdapter con customerSurveyList y establece el adaptador para RecyclerView a CustomerSurveysAdapter, que ahora muestra la lista de encuestas a la UI.

El IDE te pedirá que añadas la importación de SurveyListItem. Si no lo hace, añada esta importación:

import com.raywenderlich.android.customersurveys.customersurveys.SurveyListItem

Ahora que ha mostrado los datos a la UI, sólo tiene unos pocos pasos más para que todo funcione perfectamente.

A continuación, añadirás el código que se encarga de obtener los datos de Room dependiendo de la opción seleccionada en el desplegable de la interfaz de usuario, es decir, el widget Spinner.

Obtención de datos para las diferentes vistas

Añade el siguiente trozo de código justo debajo de onCreate en AllSurveysFragment.kt::

private fun spinnerListener() { filterSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onNothingSelected(parent: AdapterView<*>?) {} override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { when (position) { 0 -> resetState() 1 -> getAllCustomerSurveys() 2 -> getHappyBreakfastCustomers() 3 -> getSadDinnerCustomers() 4 -> getAverageLunchCustomers() 5 -> getQuestionOneSadCustomers() } } }}

El trozo de código anterior establece onItemSelectedListener en filterSpinner y anula dos métodos: onNothingSelected y onItemSelected. No quieres hacer nada cuando no hay nada seleccionado, así que onNothingSelected se deja vacío. Sí se quiere reaccionar cuando se selecciona un elemento, por lo que hay que implementar onItemSelected.

onItemSelected tiene una expresión when que llama a diferentes métodos dependiendo de la opción seleccionada en filterSpinner. Estos métodos son similares a getHappyBreakfastCustomers(), pero obtienen los datos utilizando un DatabaseView diferente.

Asegúrate de añadir las importaciones cuando el IDE te lo pida.

Por último, añade una llamada a spinnerListener() dentro de onViewCreated, justo después de setupSpinner(), como se muestra a continuación:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setupSpinner() // Added spinnerListener()}

Ahora que tienes todo listo para obtener las encuestas, tu siguiente paso es añadir el código para navegar a AllSurveysFragment.

Navegar a Todas las Encuestas

Este es el último paso que necesitas para ver las vistas en acción.

Navega a completedsurvey/SurveyCompletedFragment.kt y descomenta el código dentro de btnViewSurveys. Su resultado final se verá así:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) btnViewSurveys.setOnClickListener { findNavController() .navigate(R.id.action_surveyCompletedFragment_to_allSurveysFragment) }}

Aquí, simplemente está estableciendo el oyente de clic para el botón VIEW SURVEYS y navegando a AllSurveysFragment.

Una vez que descomente el código, el IDE le pedirá que importe findNavController(). Simplemente importe lo requerido.

Construya, ejecute e inicie una encuesta, luego conteste las preguntas y envíelas. Por último, visualiza Todas las encuestas, donde podrás obtener todos los datos en función de la opción que hayas seleccionado en el spinner.

Opciones del spinner en la app
Lista de clientes contentos en promedio utilizando una Vista de base de datos
Los clientes de la cena no se encuentran utilizando una Vista de base de datos

¡Felicidades! Has terminado tu experiencia en el restaurante The View. Esperemos que hayas tenido una gran comida, hayas visto vistas increíbles y hayas tenido la oportunidad de aprender lo que son las DatabaseViews.

¿A dónde ir desde aquí?

Descarga el proyecto final utilizando el botón de descarga de materiales en la parte superior o inferior del tutorial.

Para obtener más información sobre las características de Room, consulta la documentación oficial de Android.

Esperamos que hayas disfrutado de este tutorial de Room Database Views. Si usted tiene alguna pregunta, comentarios o modificaciones impresionantes a este proyecto de aplicación, por favor únase a la discusión del foro a continuación.

raywenderlich.com Weekly

El boletín raywenderlich.com es la forma más fácil de mantenerse al día sobre todo lo que necesita saber como desarrollador móvil.

Obtenga un resumen semanal de nuestros tutoriales y cursos, y reciba un curso gratuito en profundidad por correo electrónico como bonificación

Valoración media

4.8/5

Añadir una valoración para este contenido

Iniciar sesión para añadir una valoración

10 valoraciones

.

Leave a Reply