Nozioni di base su Android Kotlin 02.4: nozioni di base sul collegamento di dati

Questo codelab fa parte del corso Android Kotlin Fundamentals. Otterrai il massimo valore da questo corso se lavori in sequenza nei codelab. Tutti i codelab del corso sono elencati nella pagina di destinazione di Android Kotlin Fundamentals.

Introduzione

Nei codelab precedenti di questo corso, hai utilizzato la funzione findViewById() per ottenere riferimenti alle viste. Se la tua app ha gerarchie di visualizzazioni complesse, findViewById() è costosa e rallenta. Android attraversa la gerarchia di visualizzazione, a partire dalla radice, finché non trova la vista desiderata. Fortunatamente, c'è un modo migliore.

Per impostare i dati nelle viste, hai utilizzato risorse di tipo stringa e hai impostato i dati dell'attività. Sarebbe più efficiente se la vista sapesse dei dati. Per fortuna, è tutto possibile.

In questo codelab, imparerai a utilizzare l'associazione di dati per eliminare la necessità di findViewById(). Imparerai anche a utilizzare l'associazione di dati per accedere ai dati direttamente da una vista.

Informazioni importanti

Dovresti acquisire familiarità con:

  • Che cos'è un'attività e come configurarla con un layout in onCreate().
  • Creazione di una visualizzazione di testo e impostazione del testo visualizzato.
  • Utilizzare findViewById() per ottenere un riferimento a una vista.
  • Creazione e modifica di un layout XML di base per una vista.

Obiettivi didattici

  • Come utilizzare la libreria di associazione di dati per eliminare le chiamate inefficienti verso findViewById().
  • Come accedere ai dati delle app direttamente da XML.

In questo lab proverai a:

  • Modifica un'app in modo che utilizzi l'associazione di dati invece di findViewById() per accedere ai dati direttamente dai file XML di layout.

In questo codelab, inizierai dall'app Informazioni su me e cambi l'app in modo che utilizzi l'associazione di dati. L'app avrà esattamente lo stesso aspetto al termine dell'operazione.

Ecco cosa fa l'app Informazioni su di me:

  • Quando l'utente apre l'app, l'app mostra un nome, un campo per inserire un nickname, un pulsante Fine, un'immagine a stella e testo scorrevole.
  • L'utente può inserire un nickname e toccare il pulsante Fine. Il campo e il pulsante modificabili sono sostituiti da una visualizzazione di testo che mostra il nickname inserito.


Puoi utilizzare il codice creato nel codelab precedente oppure scaricare il codice AboutMeDataBinding-Starter da GitHub.

Il codice che hai scritto nei codelab precedenti utilizza la funzione findViewById() per ottenere riferimenti alle viste.

Ogni volta che utilizzi findViewById() per cercare una vista dopo averla creata o ricreata, il sistema Android attraversa la gerarchia di visualizzazioni al momento dell'esecuzione. Anche se la tua app ha solo poche visualizzazioni, non è un problema. Tuttavia, le app di produzione potrebbero avere decine di visualizzazioni in un layout e, anche con il design migliore, ci saranno viste nidificate.

Pensa a un layout lineare che contiene una visualizzazione di scorrimento che contiene una visualizzazione di testo. Nel caso di una gerarchia di visualizzazione grande o profonda, trovare una visualizzazione può richiedere tempo tale da rallentare notevolmente l'app per l'utente. La memorizzazione delle variabili nella cache può essere utile, ma devi comunque inizializzare una variabile per ogni vista in ogni spazio dei nomi. Con molte visualizzazioni e diverse attività, tutto questo si aggiunge.

Una soluzione è creare un oggetto contenente un riferimento a ogni vista. Questo oggetto, chiamato oggetto Binding, può essere utilizzato dall'intera app. Questa tecnica è chiamata associazione di dati. Dopo aver creato un oggetto di associazione per la tua app, puoi accedere alle viste e ad altri dati tramite l'oggetto di associazione, senza dover attraversare la gerarchia delle visualizzazioni o cercare i dati.

L'associazione di dati offre i seguenti vantaggi:

  • Il codice è più breve, più facile da leggere e più facile da gestire rispetto a quello che utilizza findByView().
  • I dati e le viste sono separati chiaramente. Questo vantaggio legato all'associazione di dati diventa sempre più importante alla fine di questo corso.
  • Il sistema Android attraversa la gerarchia di visualizzazione solo una volta per ottenere ogni visualizzazione e si verifica durante l'avvio dell'app, non in fase di runtime quando l'utente interagisce con l'app.
  • Hai sicurezza del tipo per accedere alle viste. Con Sicurezza del tipo, il compilatore convalida i tipi durante la compilazione e genera un errore se tenti di assegnare il tipo sbagliato a una variabile.

In questa attività devi configurare l'associazione di dati e utilizzare l'associazione di dati per sostituire le chiamate a findViewById() con le chiamate all'oggetto di associazione.

Passaggio 1: attiva l'associazione di dati

Per utilizzare l'associazione di dati, devi attivare l'associazione di dati nel tuo file Gradle, in quanto non è abilitata per impostazione predefinita. Questo perché l'associazione di dati aumenta il tempo di compilazione e potrebbe influire sul tempo di avvio dell'app.

  1. Se non hai l'app Informazioni su un codelab precedente, recupera il codice AboutMeDataBinding-Starter di GitHub. Aprilo in Android Studio.
  2. Apri il file build.gradle (Module: app).
  3. All'interno della sezione android, prima della parentesi di chiusura, aggiungi una sezione dataBinding e imposta enabled su true.
dataBinding {
    enabled = true
}
  1. Quando richiesto, sincronizza il progetto. Se non ti viene richiesto, seleziona File > Sync Project with Gradle Files.
  2. Puoi eseguire l'app, ma non noterai cambiamenti.

Passaggio 2: modifica il file di layout in modo che sia utilizzabile con l'associazione di dati

Per utilizzare l'associazione di dati, devi aggregare il layout XML a un tag <layout>. In questo modo la classe principale non è più un gruppo di viste, ma è un layout che contiene gruppi di viste e viste. L'oggetto vincolante può quindi conoscere il layout e le viste al suo interno.

  1. Apri il file activity_main.xml.
  2. Passa alla scheda Testo.
  3. Aggiungi <layout></layout> come tag più esterno attorno a <LinearLayout>.
<layout>
   <LinearLayout ... >
   ...
   </LinearLayout>
</layout>
  1. Scegli Codice &Riformatta il codice per correggere il rientro del codice.

    Le dichiarazioni dello spazio dei nomi per un layout devono essere nel tag più esterno.
  1. Taglia le dichiarazioni dello spazio dei nomi da <LinearLayout> e incollale nel tag <layout>. Il tag di apertura <layout> dovrebbe apparire come mostrato di seguito, mentre il tag <LinearLayout> deve contenere solo proprietà di visualizzazione.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
  1. Crea ed esegui la tua app per verificare di averlo fatto correttamente.

Passaggio 3: crea un oggetto vincolante nell'attività principale

Aggiungi un riferimento all'oggetto binding all'attività principale, in modo da poterlo utilizzare per accedere alle viste:

  1. Apri il file MainActivity.kt.
  2. Prima del giorno onCreate(), al livello superiore, crea una variabile per l'oggetto binding. Questa variabile è in genere denominata binding.

    Il tipo di binding, la classe ActivityMainBinding, viene creato dal compilatore appositamente per questa attività principale. Il nome deriva dal nome del file di layout, ovvero activity_main + Binding.
private lateinit var binding: ActivityMainBinding
  1. Se richiesto da Android Studio, importa ActivityMainBinding. Se non ti viene richiesto, fai clic su ActivityMainBinding e premi Alt+Enter (Option+Enter su Mac) per importare il corso mancante. Per ulteriori scorciatoie da tastiera, consulta Scorciatoie da tastiera.

    L'istruzione import dovrebbe essere simile a quella mostrata di seguito.
import com.example.android.aboutme.databinding.ActivityMainBinding

Successivamente, sostituisci la funzione setContentView() corrente con un'istruzione che esegue le seguenti operazioni:

  • Crea l'oggetto di associazione.
  • Utilizza la funzione setContentView() della classe DataBindingUtil per associare il layout activity_main a MainActivity. Questa funzione setContentView() si occupa anche di alcune configurazioni di associazione di dati per le viste.
  1. In onCreate(), sostituisci la chiamata setContentView() con la seguente riga di codice.
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
  1. Importa DataBindingUtil.
import androidx.databinding.DataBindingUtil

Passaggio 4: utilizza l'oggetto binding per sostituire tutte le chiamate afindViewById()

Ora puoi sostituire tutte le chiamate a findViewById() con i riferimenti alle viste presenti nell'oggetto binding. Quando viene creato l'oggetto di associazione, il compilatore genera i nomi delle viste nell'oggetto di associazione dagli ID delle viste nel layout, convertendoli in lettere maiuscole. Quindi, ad esempio, done_button è doneButton nell'oggetto binding, nickname_edit diventa nicknameEdit e nickname_text diventa nicknameText.

  1. In onCreate(), sostituisci il codice che utilizza findViewById() per trovare l'elemento done_button con il codice che fa riferimento al pulsante nell'oggetto di associazione.

    Sostituisci questo codice: findViewById<Button>(R.id.done_button)
    con: binding.doneButton

    Il codice completo per impostare il listener di clic in onCreate() dovrebbe avere questo aspetto.
binding.doneButton.setOnClickListener {
   addNickname(it)
}
  1. Ripeti l'operazione per tutte le chiamate a findViewById() nella funzione addNickname().
    Sostituisci tutte le occorrenze di findViewById<View>(R.id.id_view) con binding.idView. Esegui questa operazione nel seguente modo:
  • Elimina le definizioni delle variabili editText e nicknameTextView insieme alle relative chiamate a findViewById(). Verranno visualizzati errori.
  • Correggi gli errori recuperando le visualizzazioni nicknameText, nicknameEdit e doneButton dall'oggetto binding anziché le variabili (eliminate).
  • Sostituisci view.visibility con binding.doneButton.visibility. Se utilizzi binding.doneButton invece di view, il codice diventa più coerente.

    Il risultato è il seguente codice:
binding.nicknameText.text = binding.nicknameEdit.text
binding.nicknameEdit.visibility = View.GONE
binding.doneButton.visibility = View.GONE
binding.nicknameText.visibility = View.VISIBLE
  • Le funzionalità non subiranno modifiche. Facoltativamente, ora puoi eliminare il parametro view e aggiornare tutti gli utilizzi di view in modo che utilizzino binding.doneButton all'interno di questa funzione.
  1. nicknameText richiede un String e nicknameEdit.text è un Editable. Quando utilizzi l'associazione di dati, devi convertire esplicitamente Editable in un String.
binding.nicknameText.text = binding.nicknameEdit.text.toString()
  1. Puoi eliminare le importazioni non selezionabili.
  2. Kotlinizza la funzione utilizzando apply{}.
binding.apply {
   nicknameText.text = nicknameEdit.text.toString()
   nicknameEdit.visibility = View.GONE
   doneButton.visibility = View.GONE
   nicknameText.visibility = View.VISIBLE
}
  1. Crea ed esegui la tua app: l'aspetto dovrebbe essere lo stesso di prima.

Puoi utilizzare l'associazione di dati per rendere una classe di dati direttamente disponibile per una vista. Questa tecnica semplifica il codice ed è molto utile per la gestione di richieste più complesse.

Per questo esempio, invece di impostare il nome e il nickname utilizzando le risorse stringa, crei una classe dati per il nome e il nickname. La classe dati diventa disponibile per la vista utilizzando l'associazione di dati.

Passaggio 1: crea la classe di dati MyName

  1. In Android Studio nella directory java, apri il file MyName.kt. Se non hai questo file, crea un nuovo file Kotlin e chiamalo MyName.kt.
  2. Definisci una classe di dati per il nome e il nickname. Utilizza le stringhe vuote come valori predefiniti.
data class MyName(var name: String = "", var nickname: String = "")

Passaggio 2: aggiungi dati al layout

Nel file activity_main.xml, il nome è attualmente impostato in un elemento TextView di una risorsa stringa. Devi sostituire il riferimento al nome con un riferimento ai dati nella classe dati.

  1. Apri activity_main.xml nella scheda Testo.
  2. Nella parte superiore del layout, tra i tag <layout> e <LinearLayout>, inserisci un tag <data></data>. Qui colleghi la vista ai dati.
<data>
  
</data>

All'interno dei tag dei dati, puoi dichiarare le variabili denominate che contengono un riferimento a una classe.

  1. All'interno del tag <data>, aggiungi un tag <variable>.
  2. Aggiungi un parametro name per assegnare alla variabile un nome "myName". Aggiungi un parametro type e imposta il tipo su un nome completo della classe di dati MyName (nome pacchetto + nome variabile).
<variable
       name="myName"
       type="com.example.android.aboutme.MyName" />

Ora, invece di utilizzare la risorsa stringa per il nome, puoi fare riferimento alla variabile myName.

  1. Sostituisci android:text="@string/name" con il codice riportato di seguito.

@={} è un'istruzione per recuperare i dati a cui viene fatto riferimento all'interno delle parentesi graffe.

myName fa riferimento alla variabile myName definita in precedenza, che rimanda alla classe dei dati myName e recupera la proprietà name dalla classe.

android:text="@={myName.name}"

Passaggio 3: crea i dati

Ora puoi fare riferimento ai dati nel tuo file di layout. Il passaggio successivo consiste nel creare i dati effettivi.

  1. Apri il file MainActivity.kt.
  2. Sopra onCreate(), crea una variabile privata, chiamata anche myName per convenzione. Assegna alla variabile un'istanza della classe dati MyName, trasmettendo il nome.
private val myName: MyName = MyName("Aleks Haecky")
  1. In onCreate(), imposta il valore della variabile myName nel file di layout sul valore della variabile myName appena dichiarato. Non puoi accedere direttamente alla variabile nel file XML. È necessario accedervi tramite l'oggetto binding.
binding.myName = myName
  1. Questo potrebbe causare un errore perché è necessario aggiornare l'oggetto binding dopo aver apportato modifiche. Crea la tua app e l'errore dovrebbe scomparire.

Passaggio 4: utilizza la classe di dati per il nickname in TextView

Il passaggio finale consiste nell'utilizzare la classe dei dati per il nickname in TextView.

  1. Apri activity_main.xml.
  2. Aggiungi una proprietà text nella visualizzazione di testo nickname_text. Fai riferimento all'elemento nickname nella classe dei dati, come mostrato di seguito.
android:text="@={myName.nickname}"
  1. In ActivityMain, sostituisci
    nicknameText.text = nicknameEdit.text.toString()
    con il codice per impostare il nickname nella variabile myName.
myName?.nickname = nicknameEdit.text.toString()

Dopo aver impostato il nickname, vuoi che il codice aggiorni l'interfaccia utente con i nuovi dati. Per farlo, devi annullare tutte le espressioni di associazione in modo che vengano ricreate con i dati corretti.

  1. Aggiungi invalidateAll() dopo aver impostato il nickname in modo che l'interfaccia utente venga aggiornata con il valore dell'oggetto binding aggiornato.
binding.apply {
   myName?.nickname = nicknameEdit.text.toString()
   invalidateAll()
   ...
}
  1. Crea ed esegui la tua app, che dovrebbe funzionare esattamente come prima.

Progetto Android Studio: AboutMeDataBinding

Per utilizzare l'associazione di dati per sostituire le chiamate con findViewById():

  1. Attiva l'associazione di dati nella sezione Android del file build.gradle:
    dataBinding { enabled = true }
  2. Utilizza <layout> come visualizzazione principale nel layout XML.
  3. Definisci una variabile di associazione:
    private lateinit var binding: ActivityMainBinding
  4. Crea un oggetto vincolante in MainActivity sostituendo setContentView:
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
  5. Sostituisci le chiamate a findViewById() con riferimenti alla vista nell'oggetto vincolante. Ad esempio:
    findViewById<Button>(R.id.done_button) ⇒ binding.doneButton
    (in questo esempio, il nome della vista è generato nel formato cammello della vista id della vista nel file XML.)

Passaggi per associare le viste ai dati:

  1. Crea una classe per i tuoi dati.
  2. Aggiungi un blocco <data> all'interno del tag <layout>.
  3. Definisci un <variable> con un nome e un tipo che sia la classe dei dati.
<data>
   <variable
       name="myName"
       type="com.example.android.aboutme.MyName" />
</data>
  1. In MainActivity, crea una variabile con un'istanza della classe di dati. Ad esempio:
    private val myName: MyName = MyName("Aleks Haecky")
  1. Nell'oggetto binding, imposta la variabile su quella appena creata:
    binding.myName = myName
  1. Nel file XML, imposta i contenuti della vista sulla variabile che hai definito nel blocco <data>. Utilizza la notazione dei punti per accedere ai dati all'interno della classe dati.
    android:text="@={myName.name}"

Corso Udacity:

Documentazione per gli sviluppatori Android:

In questa sezione sono elencati i possibili compiti per gli studenti che lavorano attraverso questo codelab nell'ambito di un corso tenuto da un insegnante. Spetta all'insegnante fare quanto segue:

  • Assegna i compiti, se necessario.
  • Comunica agli studenti come inviare compiti.
  • Valuta i compiti.

Gli insegnanti possono utilizzare i suggerimenti solo quanto e come vogliono e dovrebbero assegnare i compiti che ritengono appropriati.

Se stai lavorando da solo a questo codelab, puoi utilizzare questi compiti per mettere alla prova le tue conoscenze.

Rispondi a queste domande

Domanda 1

Perché vuoi ridurre al minimo le chiamate esplicite e implicite a findViewById()?

  • Ogni volta che viene chiamato, findViewById() attraversa la gerarchia di visualizzazioni.
  • findViewById() viene eseguito sul thread principale o sull'interfaccia utente.
  • Queste chiamate possono rallentare l'interfaccia utente.
  • La tua app ha meno probabilità di arrestarsi in modo anomalo.

Domanda 2

Come descriveresti l'associazione di dati?

Ad esempio, ecco alcune informazioni che potresti fornire in merito all'associazione di dati:

  • La grande idea dell'associazione di dati consiste nel creare un oggetto che permetta di collegare/mappare/vincolare due informazioni lontane tra loro al momento della compilazione, in modo da non dover cercare i dati in fase di esecuzione.
  • L'oggetto che mostra queste associazioni è chiamato oggetto collegamento.
  • L'oggetto di associazione viene creato dal compilatore.

Domanda 3

Quale dei seguenti NON è un vantaggio dell'associazione di dati?

  • Il codice è più breve, più facile da leggere e da gestire.
  • I dati e le viste sono separati chiaramente.
  • Il sistema Android attraversa la gerarchia di visualizzazioni solo una volta per ottenere ogni visualizzazione.
  • La chiamata a findViewById() genera un errore di compilazione.
  • Digita sicurezza per l'accesso alle viste.

Domanda 4

Qual è la funzione del tag <layout>?

  • Arrotolalo intorno alla visualizzazione principale nel layout.
  • Le associazioni vengono create per tutte le viste di un layout.
  • Indica la visualizzazione di primo livello in un layout XML che utilizza l'associazione di dati.
  • Puoi utilizzare il tag <data> all'interno di un elemento <layout> per associare una variabile a una classe di dati.

Domanda 5

Qual è il modo corretto per fare riferimento ai dati associati nel layout XML?

  • android:text="@={myDataClass.property}"
  • android:text="@={myDataClass}"
  • android:text="@={myDataClass.property.toString()}"
  • android:text="@={myDataClass.bound_data.property}"

Inizia la lezione successiva: 3.1: Creare un frammento

Per i link ad altri codelab in questo corso, consulta la pagina di destinazione di Android Kotlin Fundamentals.