Viste di database con Room per Android

Room è uno strato di astrazione sopra SQLite che Google ha confezionato come libreria AndroidX e che raccomanda anche. Dalla versione 2.1, Room offre la possibilità di aggiungere Database Views, note anche come query memorizzate.

Alcuni dei buoni motivi per utilizzare le Database Views sarebbero:

  • Rendono facile per voi scrivere query complesse e utilizzarle in query Data Access Object (DAO).
  • Puoi interrogare solo i campi di cui hai bisogno, piuttosto che dover passare attraverso tutti i campi di una tabella.

In questo tutorial, costruirai un’applicazione Customer Surveys che permette ai clienti di un ristorante di lasciare un feedback, poi salva il feedback nel database gestito dalla Room. Durante il processo imparerai quanto segue:

  • Cos’è una vista di database?
  • Come creare viste di database?
  • Come usarle per semplificare la scrittura di query SELECT
Nota: Questo tutorial presuppone che tu abbia esperienza nello sviluppo per Android in Kotlin e che tu abbia già lavorato con Room. Se non hai familiarità con Room, dai un’occhiata al nostro tutorial Data Persistence with Room.

Questo tutorial usa anche le Coroutine con Room. Per saperne di più, leggete il nostro tutorial Coroutines With Room Persistence Library.

Iniziare

Scaricate il progetto iniziale facendo clic sul pulsante Scarica materiali all’inizio o alla fine di questo tutorial.

Estraete il file ZIP e aprite il progetto iniziale in Android Studio 4.0 o successivo selezionando Open an existing Android Studio project dalla schermata di benvenuto.

Una volta completata la sincronizzazione con Gradle, esplorate la struttura del progetto. Il progetto segue l’architettura MVVM, quindi funzionalità simili sono sotto un unico pacchetto. Familiarizza con i pacchetti presenti – li userai in questo tutorial.

Costruisci ed esegui. Vedrai una semplice schermata con un messaggio di benvenuto, un’immagine e un pulsante START SURVEY.

Schermo d'inizio dell'indagine dell'applicazione Indagini sui clienti

Tocca il pulsante INIZIA L’INDAGINE. Per lo scopo di questo tutorial, puoi ignorare il fatto che non hai mangiato al ristorante. :]

La prossima schermata è quella del sondaggio. Ha un campo di input e-mail, pulsanti radio per scegliere il pasto che stai valutando e tre domande. Ogni domanda ha i pulsanti Buono, Medio e Cattivo sotto di loro, in modo che l’utente possa valutare la propria soddisfazione.

Schermo del sondaggio della app Customer Surveys con domande e possibili valutazioni

Vedrai anche il pulsante SUBMIT SURVEY. Toccalo e vedrai un brindisi che dice che non è ancora il momento di fare il sondaggio. Non preoccuparti, lo risolverai nel corso di questo tutorial.

Ti è stato dato il benvenuto al The View Restaurant, dove potrai vedere incredibili viste sulla natura, assaggiare i loro deliziosi piatti e valutare la tua soddisfazione. Già che ci sei, imparerai anche le visualizzazioni del database di Room.

Usare le visualizzazioni del database

Considera una tabella che ha funzionalità extra di query SELECT preconfezionate per comodità. Le versioni 2.1 e superiori di Room le chiamano viste di database e forniscono un’annotazione con lo stesso nome, cioè @DatabaseView.

Utilizzando questa annotazione potete marcare una classe per comportarsi come una Vista del database. Questo vi permetterà di allegare una query alla classe, come sotto:

@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}

Potete quindi usare questa classe nel vostro DAO per interrogare i dati nello stesso modo in cui fareste con una classe contrassegnata come Entità, cioè Tabella in un database.

Un DAO vi aiuta ad accedere ai dati dal database della vostra applicazione. Tipicamente contiene i metodi CUD (Create, Update and Delete) e può anche contenere altri metodi che possono essere necessari per l’accesso in lettura e scrittura al database.

La relazione tra le Viste del database e il database è simile alla relazione tra entità e il database. Daremo un’occhiata più approfondita a queste relazioni dopo.

Confronto tra una vista di database e un’entità

Le classi annotate con @DatabaseView sono simili alle classi Entity. Ecco come:

  • Entrambe possono usare SELECT FROM nelle query DAO.
  • Database Views e Entitys possono entrambe usare @ColumnInfo, che permette di personalizzare le informazioni delle colonne associate ad un campo.
  • Possono entrambe usare @Embedded, che permette ad un campo di avere campi annidati che le query possono referenziare direttamente.

Mentre ci sono molte somiglianze tra i due, ci sono anche differenze tra DatabaseView e Entity:

  • Puoi usare INSERT, UPDATE e DELETE con un Entity, ma non con un DatabaseView.
  • Definirai tutte le tue viste nelle tue applicazioni usando views, ma definisci le entità usando entities.

Ora che sai cos’è un DatabaseView e come si confronta e contrasta con una classe Entity, è ora di usarlo e iniziare a presentare il sondaggio per The View Restaurant.

Invio dell’indagine

Il tuo primo passo è aggiungere la logica per inviare l’indagine e salvarla nel database di Room dopo aver toccato il pulsante SUBMIT SURVEY.

Passa a customersurveys/CustomerSurveyFragment.kt, dove aggiungerai la logica per raccogliere le risposte e salvarle in Room. Fallo sostituendo il codice in submitSurvey() con questo:

// 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)}

Ecco cosa stai facendo con questo codice:

  1. Prendi l’email da editEmail e assegnala a una variabile: email.
  2. Questo controllo di condizione chiama validateEmail(email), che controlla se l’email è null o no. Restituisce false se è null. Controlla anche se l’email inserita è valida e restituisce false se non lo è.
  3. Il codice dentro l’istruzione if viene eseguito quando validateEmail(email) restituisce true. meal tiene il tipo di pasto che l’utente ha selezionato dai gruppi radio.
  4. Una volta che avete il valore di meal, create SurveyListItem.CustomerSurvey, che ha tutte le informazioni sul sondaggio. Esso estrae i valori di questionOneAnswer, questionTwoAnswer e questionThreeAnswer da toggleButtonListeners(), che ha degli ascoltatori per questo scopo.
  5. Qui si salva customerSurvey chiamando insertCustomerSurvey(customerSurvey) in CustomerSurveyViewModel, che gestisce la logica per salvare in Room.
  6. Passa a SurveyCompletedFragment.

Dopo aver aggiunto questo, noterai che customerSurveyViewModel e findNavController() hanno delle sottolineature rosse. Per risolvere questo problema, aggiungete prima l’inizializzazione CustomerSurveyViewModel all’inizio della classe, appena sotto l’inizializzazione questionThreeAnswer.

private val customerSurveyViewModel: CustomerSurveyViewModel by viewModels()

Assicuratevi di aggiungere le rispettive dichiarazioni di importazione quando l’IDE ve lo chiede.

Costruisci ed esegui. Avvia il sondaggio, inserisci l’email richiesta e seleziona le tue risposte alle domande.

Schermo del sondaggio con le risposte

Bene, hai completato il sondaggio.

Visualizza tutti i sondaggi usando la schermata delle viste del database

Tocca il pulsante VIEW SURVEYS… oops, non fa ancora niente. Non preoccuparti, lo risolverai presto.

Nella prossima sezione, imparerai come creare il tuo primo DatabaseView.

Creazione di una vista sul database

Per creare una vista, aggiungerai un’annotazione @DatabaseView a una classe o a una classe dati. Iniziate navigando verso customersurveys/SurveyListItem.kt. Questa è una classe sigillata con un paio di classi di dati da usare in questo tutorial.

In fondo a SurveyListItem, appena sotto QuestionOneSadView, aggiungete quanto segue:

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

Questa classe di dati sovrascrive la variabile email da SurveyListItem ed eredita dalla classe – cioè è un sottotipo di SurveyListItem.

Dopo aver creato questa classe di dati, aggiungete @DatabaseView con una query SELECT per recuperare tutti gli id delle e-mail dalla tabella CustomerSurvey dove il pasto è impostato su “Breakfast”, appena sopra la classe di dati HappyBreakFastView. La tua annotazione dovrebbe essere simile a questa:

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

Alcune cose da notare sulla query all’interno dell’annotazione:

  • La query funziona come qualsiasi altra query che hai scritto in Room.
  • Devi richiedere tutti i campi che hai nella tua classe dati mentre scrivi la query. In questo caso, avete bisogno solo dell’email. Usa SELECT CustomerSurvey.email From... per ottenere l’e-mail da CustomerSurvey.
Nota: per questo tutorial, mantieni le viste e l’entità all’interno di SurveyListItem per evitare ripetizioni e per rendere il codice più facile da leggere. Non devi sempre sottoclasse le tue viste in una classe sigillata; possono anche essere in un proprio file o classe separata.

Congratulazioni, hai creato la tua prima vista! Ora vedrai come puoi usare la vista nelle tue query DAO.

Using Room Database Views in DAO Queries

Primo, includerai HappyBreakFastView in views nel @Database dell’app.

Passa a database/AppDatabase.kt e, dentro views, aggiungi SurveyListItem.HappyBreakFastView::class. La tua annotazione @Database aggiornata dovrebbe apparire come segue:

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

Nota che il version = 2. Devi aggiornare la versione del database ogni volta che aggiungi un view nell’AppDatabase – altrimenti la tua app andrà in crash. In questo caso, hai aggiornato la versione a 2. Sincronizza gradle per applicare tutte queste modifiche.

Poi, naviga verso customers/CustomerSurveysDao.kt e, proprio sotto getQuestionOneSadView(), aggiungi il seguente codice:

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

Questo metodo ottiene dal ristorante tutti i clienti che sono rimasti soddisfatti di qualsiasi aspetto del sondaggio. Per spiegarlo più dettagliatamente:

  • Primo, usate HappyBreakFastView come fareste in una normale query.
  • Chiamate questo metodo in CustomerSurveyRepo per ottenere una lista di tutti i clienti che hanno risposto a qualsiasi domanda con Buono. Notate che il tipo di ritorno del metodo è una lista LiveData di tipo SurveyListItem.HappyBreakFastView, che è un titolare di variabile osservabile.

Ora, avete creato un view e il metodo per interrogare la lista dei clienti che hanno risposto con una risposta positiva in CustomerSurveysDao. Nella prossima sezione, imparerai come chiamare questo metodo dalla classe repository.

Fetching Data Using a DatabaseView

Passa a customersurveys/CustomerSurveyRepo.kt e aggiungi il seguente metodo appena sotto getQuestionOneSadView():

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

Questo metodo chiama getHappyBreakFastCustomers() da CustomerSurveysDao per ottenere i dati da Room. Il suo tipo di ritorno è un LiveData, che permette a chi chiama questo metodo di osservare qualsiasi cambiamento nei dati.

Poi, aggiungerai una chiamata a getHappyBreakFastCustomers() in CustomerSurveyViewModel. È responsabile della visualizzazione dei dati alla vista – che, in questo caso, non è DatabaseView ma AllSurveysFragment.

Passa a customersurveys/CustomerSurveyViewModel.kt e aggiungi il seguente codice:

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

Questa variabile ottiene il suo valore chiamando getHappyBreakFastCustomers() da CustomerSurveyRepo. C’è un by lazy{} in modo da non caricare i dati immediatamente, ma piuttosto quando si accede per la prima volta alla variabile.

Poi, aggiornerai l’UI in modo che possa visualizzare i dati.

Visualizzazione dei dati nell’UI

Passa a allsurveys/AllSurveysFragment.kt e aggiungi il seguente codice in fondo alla classe:

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}

Per spiegare cosa fa il codice:

  • Prima di tutto, chiama happyBreakfastCustomers e osserva il suo valore.
  • Dentro la lambda observe, c’è un controllo per vedere se customerSurveyList è null o no. Se la lista è null, si imposta il messaggio No surveys found! di TextView su visible e si nasconde RecyclerView. Se non è null, imposti la visibilità di TextView su GONE e mostri RecyclerView. Chiamate anche initView(customerSurveyList) con il valore customerSurveyList di CustomerSurveyViewModel.
  • initView(customerSurveySurveyList: List) inizializza CustomerSurveysAdapter con customerSurveyList e imposta l’adattatore per RecyclerView a CustomerSurveysAdapter, che ora visualizza la lista dei sondaggi nell’UI.

L’IDE vi chiederà di aggiungere l’importazione SurveyListItem. Se non lo fa, aggiungi questa importazione:

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

Ora che hai visualizzato i dati nell’interfaccia utente, hai solo pochi altri passaggi prima che tutto funzioni perfettamente.

Prossimo, aggiungerai il codice che gestisce il recupero dei dati da Room a seconda dell’opzione selezionata sul dropdown nell’interfaccia utente, cioè il widget Spinner.

Fetching Data for the Different Views

Aggiungi il seguente pezzo di codice appena sotto onCreate in 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() } } }}

Il pezzo di codice sopra imposta onItemSelectedListener a filterSpinner e sovrascrive due metodi: onNothingSelected e onItemSelected. Non volete fare nulla quando non è selezionato nulla, quindi onNothingSelected è lasciato vuoto. Vuoi reagire a quando un elemento è selezionato, quindi hai bisogno di implementare onItemSelected.

onItemSelected ha un’espressione when che chiama diversi metodi a seconda dell’opzione selezionata in filterSpinner. Questi metodi sono simili a getHappyBreakfastCustomers(), ma recuperano i dati usando un diverso DatabaseView.

Assicurati di aggiungere le importazioni quando l’IDE te lo chiede.

Infine, aggiungi una chiamata a spinnerListener() dentro onViewCreated, subito dopo setupSpinner(), come mostrato sotto:

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

Ora che hai tutto pronto per recuperare le indagini, il tuo prossimo passo è aggiungere il codice per navigare verso AllSurveysFragment.

Navigare verso tutti i sondaggi

Questo è l’ultimo passo di cui hai bisogno per vedere le viste in azione.

Vai a completedsurvey/SurveyCompletedFragment.kt e decommenta il codice dentro btnViewSurveys. Il tuo risultato finale sarà simile a questo:

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

Qui, stai semplicemente impostando l’ascoltatore di click per il pulsante VIEW SURVEYS e navigando verso AllSurveysFragment.

Una volta decommentato il codice, l’IDE ti chiederà di importare findNavController(). Importa semplicemente il richiesto.

Costruisci, esegui e avvia un sondaggio, poi rispondi alle domande e inviale. Infine, visualizza Tutti i sondaggi, dove sarai in grado di recuperare tutti i dati a seconda dell’opzione che hai selezionato sullo spinner.

Opzioni dello spinner nell'app
Elenco dei clienti mediamente felici utilizzando una vista database
Clienti con cena triste non trovati utilizzando una vista database

Congratulazioni! Hai finito la tua esperienza al ristorante The View. Speriamo che tu abbia mangiato bene, che tu abbia visto una vista fantastica e che tu abbia avuto la possibilità di imparare cosa sono le DatabaseViews.

Dove andare da qui?

Scarica il progetto finale usando il pulsante Scarica materiali in cima o in fondo al tutorial.

Per maggiori informazioni sulle caratteristiche di Room, controlla la documentazione ufficiale di Android.

Speriamo che questo tutorial di Room Database Views ti sia piaciuto. Se hai domande, commenti o fantastiche modifiche a questo progetto di app, unisciti alla discussione sul forum qui sotto.

raywenderlich.com Weekly

La newsletter di raywenderlich.com è il modo più semplice per rimanere aggiornati su tutto ciò che devi sapere come sviluppatore mobile.

Ottieni un digest settimanale dei nostri tutorial e corsi, e ricevi un corso di approfondimento gratuito via email come bonus!

Voto medio

4.8/5

Aggiungi un voto per questo contenuto

Accedi per aggiungere un voto

10 voti

Leave a Reply