Questo codelab fa parte del corso Android Kotlin Fundamentals. Per ottenere il massimo valore da questo corso, ti consigliamo di seguire le codelab in sequenza. Tutti i codelab del corso sono elencati nella pagina di destinazione dei codelab Android Kotlin Fundamentals.
Introduzione
Nei codelab precedenti di questo corso, hai utilizzato la funzione findViewById()
per ottenere riferimenti alle visualizzazioni. Quando la tua app ha gerarchie di visualizzazione complesse, findViewById()
è costoso e rallenta l'app, perché Android attraversa la gerarchia di visualizzazione, a partire dalla radice, finché non trova la visualizzazione desiderata. Fortunatamente, esiste un modo migliore.
Per impostare i dati nelle visualizzazioni, hai utilizzato le risorse stringa e impostato i dati dall'attività. Sarebbe più efficiente se la visualizzazione conoscesse i dati. Fortunatamente, anche in questo caso è possibile.
In questo codelab imparerai a utilizzare il data binding per eliminare la necessità di findViewById()
. Scoprirai anche come utilizzare il data binding per accedere ai dati direttamente da una visualizzazione.
Cosa devi già sapere
Devi avere 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.
- Utilizzo di
findViewById()
per ottenere un riferimento a una visualizzazione. - Creazione e modifica di un layout XML di base per una visualizzazione.
Obiettivi didattici
- Come utilizzare la libreria Data Binding per eliminare le chiamate inefficienti a
findViewById()
. - Come accedere ai dati delle app direttamente da XML.
In questo lab proverai a:
- Modifica un'app per utilizzare il data binding anziché
findViewById()
e per accedere ai dati direttamente dai file XML di layout.
In questo codelab, inizierai con l'app AboutMe e la modificherai in modo che utilizzi il data binding. Al termine, l'app avrà lo stesso aspetto.
Ecco cosa fa l'app AboutMe:
- Quando l'utente apre l'app, vengono visualizzati un nome, un campo per inserire un nickname, un pulsante Fine, un'immagine a forma di stella e un testo scorrevole.
- L'utente può inserire un nickname e toccare il pulsante Fine. Il campo modificabile e il pulsante vengono 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 visualizzazioni.
Ogni volta che utilizzi findViewById()
per cercare una visualizzazione dopo che è stata creata o ricreata, il sistema Android attraversa la gerarchia delle visualizzazioni in fase di runtime per trovarla. Quando la tua app ha solo poche visualizzazioni, non è un problema. Tuttavia, le app di produzione possono avere decine di visualizzazioni in un layout e, anche con il miglior design, ci saranno visualizzazioni nidificate.
Pensa a un layout lineare che contiene una visualizzazione scorrevole che contiene una visualizzazione di testo. Per una gerarchia di visualizzazione ampia o profonda, trovare una visualizzazione può richiedere un tempo sufficiente a rallentare notevolmente l'app per l'utente. La memorizzazione nella cache delle visualizzazioni nelle variabili può essere utile, ma devi comunque inizializzare una variabile per ogni visualizzazione, in ogni spazio dei nomi. Con molte visualizzazioni e più attività, anche questo contribuisce.
Una soluzione è creare un oggetto che contenga un riferimento a ogni vista. Questo oggetto, chiamato oggetto Binding
, può essere utilizzato da tutta l'app. Questa tecnica è chiamata data binding. Una volta creato un oggetto di binding per la tua app, puoi accedere alle visualizzazioni e ad altri dati tramite l'oggetto di binding, 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 da gestire rispetto al codice che utilizza
findByView()
. - Dati e visualizzazioni sono chiaramente separati. Questo vantaggio del data binding diventa sempre più importante più avanti nel corso.
- Il sistema Android attraversa la gerarchia delle visualizzazioni una sola volta per ottenere ogni visualizzazione e ciò avviene all'avvio dell'app, non in fase di runtime quando l'utente interagisce con l'app.
- Ottieni la sicurezza dei tipi per l'accesso alle visualizzazioni. (La sicurezza dei tipi indica che il compilatore convalida i tipi durante la compilazione e genera un errore se tenti di assegnare il tipo errato a una variabile.)
In questa attività, configurerai il data binding e lo utilizzerai per sostituire le chiamate a findViewById()
con chiamate all'oggetto di binding.
Passaggio 1: attiva il data binding
Per utilizzare il data binding, devi abilitarlo nel file Gradle, in quanto non è abilitato per impostazione predefinita. Questo perché il data binding aumenta il tempo di compilazione e può influire sul tempo di avvio dell'app.
- Se non hai l'app AboutMe di un precedente codelab, scarica il codice AboutMeDataBinding-Starter da GitHub. Apri il file in Android Studio.
- Apri il file
build.gradle (Module: app)
. - All'interno della sezione
android
, prima della parentesi graffa chiusa, aggiungi una sezionedataBinding
e impostaenabled
sutrue
.
dataBinding {
enabled = true
}
- Quando richiesto, sincronizza il progetto. Se non ti viene richiesto, seleziona File > Sincronizza progetto con file Gradle.
- Puoi eseguire l'app, ma non vedrai alcuna modifica.
Passaggio 2: modifica il file di layout in modo che sia utilizzabile con il data binding
Per utilizzare il data binding, devi racchiudere il layout XML con un tag <layout>
. In questo modo, la classe radice non è più un gruppo di visualizzazioni, ma un layout che contiene gruppi di visualizzazioni e visualizzazioni. L'oggetto di binding può quindi conoscere il layout e le relative visualizzazioni.
- Apri il file
activity_main.xml
. - Passa alla scheda Testo.
- Aggiungi
<layout></layout>
come tag più esterno intorno a<LinearLayout>
.
<layout>
<LinearLayout ... >
...
</LinearLayout>
</layout>
- Scegli Code > Reformat code (Codice > Riformatta codice) per correggere il rientro del codice.
Le dichiarazioni dello spazio dei nomi per un layout devono trovarsi nel tag più esterno.
- Taglia le dichiarazioni dello spazio dei nomi da
<LinearLayout>
e incollale nel tag<layout>
. Il tag di apertura<layout>
dovrebbe avere l'aspetto mostrato di seguito, mentre il tag<LinearLayout>
deve contenere solo le proprietà della visualizzazione.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
- Crea ed esegui l'app per verificare di aver eseguito correttamente questa operazione.
Passaggio 3: crea un oggetto di binding nell'attività principale
Aggiungi un riferimento all'oggetto di binding all'attività principale, in modo da poterlo utilizzare per accedere alle visualizzazioni:
- Apri il file
MainActivity.kt
. - Prima di
onCreate()
, crea una variabile per l'oggetto di binding al livello più alto. Questa variabile viene solitamente chiamatabinding
.
Il tipo dibinding
, la classeActivityMainBinding
, viene creato dal compilatore appositamente per questa attività principale. Il nome deriva dal nome del file di layout, ovveroactivity_main + Binding
.
private lateinit var binding: ActivityMainBinding
- Se richiesto da Android Studio, importa
ActivityMainBinding
. Se non ti viene richiesto, fai clic suActivityMainBinding
e premiAlt+Enter
(Option+Enter
su Mac) per importare questo corso mancante. (Per altre scorciatoie da tastiera, vedi Scorciatoie da tastiera.)
L'istruzioneimport
dovrebbe avere un aspetto simile a quella mostrata di seguito.
import com.example.android.aboutme.databinding.ActivityMainBinding
Successivamente, sostituisci l'attuale funzione setContentView()
con un'istruzione che esegue le seguenti operazioni:
- Crea l'oggetto di associazione.
- Utilizza la funzione
setContentView()
della classeDataBindingUtil
per associare il layoutactivity_main
aMainActivity
. Questa funzionesetContentView()
si occupa anche di alcune configurazioni del data binding per le visualizzazioni.
- In
onCreate()
, sostituisci la chiamatasetContentView()
con la seguente riga di codice.
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
- Importa
DataBindingUtil
.
import androidx.databinding.DataBindingUtil
Passaggio 4: utilizza l'oggetto di binding per sostituire tutte le chiamate a findViewById()
Ora puoi sostituire tutte le chiamate a findViewById()
con riferimenti alle visualizzazioni presenti nell'oggetto di binding. Quando viene creato l'oggetto di binding, il compilatore genera i nomi delle visualizzazioni nell'oggetto di binding dagli ID delle visualizzazioni nel layout, convertendoli in camel case. Quindi, ad esempio, done_button
è doneButton
nell'oggetto di binding, nickname_edit
diventa nicknameEdit
e nickname_text
diventa nicknameText
.
- In
onCreate()
, sostituisci il codice che utilizzafindViewById()
per trovaredone_button
con il codice che fa riferimento al pulsante nell'oggetto di binding.
Sostituisci questo codice:findViewById<Button>(R.id.
done_button
)
con:binding.doneButton
Il codice finito per impostare il listener di clic inonCreate()
dovrebbe avere questo aspetto.
binding.doneButton.setOnClickListener {
addNickname(it)
}
- Fai lo stesso per tutte le chiamate a
findViewById()
nella funzioneaddNickname()
.
Sostituisci tutte le occorrenze difindViewById<
View
>(R.id.
id_view
)
conbinding.
idView
. Procedi nel seguente modo:
- Elimina le definizioni delle variabili
editText
enicknameTextView
insieme alle relative chiamate afindViewById()
. Verranno visualizzati errori. - Correggi gli errori recuperando le visualizzazioni
nicknameText
,nicknameEdit
edoneButton
dall'oggettobinding
anziché dalle variabili (eliminate). - Sostituisci
view.visibility
conbinding.doneButton.visibility
. L'utilizzo dibinding.doneButton
anziché diview
passato rende il codice 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
- Non sono previste modifiche alla funzionalità. Se vuoi, ora puoi eliminare il parametro
view
e aggiornare tutti gli utilizzi diview
in modo che utilizzinobinding.doneButton
all'interno di questa funzione.
nicknameText
richiedeString
enicknameEdit.text
è unEditable
. Quando utilizzi il data binding, è necessario convertire esplicitamenteEditable
inString
.
binding.nicknameText.text = binding.nicknameEdit.text.toString()
- Puoi eliminare le importazioni visualizzate in grigio.
- Converti la funzione in Kotlin utilizzando
apply{}
.
binding.apply {
nicknameText.text = nicknameEdit.text.toString()
nicknameEdit.visibility = View.GONE
doneButton.visibility = View.GONE
nicknameText.visibility = View.VISIBLE
}
- Crea ed esegui la tua app...e dovrebbe avere lo stesso aspetto e funzionare esattamente come prima.
Puoi sfruttare il data binding per rendere una classe di dati direttamente disponibile per una vista. Questa tecnica semplifica il codice ed è estremamente utile per gestire i casi più complessi.
Per questo esempio, anziché impostare il nome e il nickname utilizzando le risorse stringa, crei una classe di dati per il nome e il nickname. Rendi disponibile la classe di dati alla visualizzazione utilizzando il data binding.
Passaggio 1: crea la classe di dati MyName
- In Android Studio, nella directory
java
, apri il fileMyName.kt
. Se non hai questo file, creane uno nuovo in Kotlin e chiamaloMyName.kt
. - Definisci una classificazione dei dati per il nome e il nickname. Utilizza stringhe vuote come valori predefiniti.
data class MyName(var name: String = "", var nickname: String = "")
Passaggio 2: aggiungi i dati al layout
Nel file activity_main.xml
, il nome è attualmente impostato in un TextView
da una risorsa stringa. Devi sostituire il riferimento al nome con un riferimento ai dati nella classe di dati.
- Apri
activity_main.xml
nella scheda Testo. - Nella parte superiore del layout, tra i tag
<layout>
e<LinearLayout>
, inserisci un tag<data></data>
. È qui che collegherai la visualizzazione ai dati.
<data>
</data>
All'interno dei tag di dati, puoi dichiarare variabili denominate che contengono un riferimento a una classe.
- All'interno del tag
<data>
, aggiungi un tag<variable>
. - Aggiungi un parametro
name
per assegnare alla variabile il nome"myName"
. Aggiungi un parametrotype
e imposta il tipo su un nome completo della classe di datiMyName
(nome del pacchetto + nome della variabile).
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
Ora, anziché utilizzare la risorsa stringa per il nome, puoi fare riferimento alla variabile myName
.
- Sostituisci
android:text="@string/name"
con il codice riportato di seguito.
@={}
è un'istruzione per ottenere i dati a cui viene fatto riferimento all'interno delle parentesi graffe.
myName
fa riferimento alla variabile myName
definita in precedenza, che punta alla classe di dati myName
e recupera la proprietà name
dalla classe.
android:text="@={myName.name}"
Passaggio 3: crea i dati
Ora hai un riferimento ai dati nel file di layout. A questo punto, crea i dati effettivi.
- Apri il file
MainActivity.kt
. - Sopra
onCreate()
, crea una variabile privata, chiamata anchemyName
per convenzione. Assegna alla variabile un'istanza della classe di datiMyName
, passando il nome.
private val myName: MyName = MyName("Aleks Haecky")
- In
onCreate()
, imposta il valore della variabilemyName
nel file di layout sul valore della variabilemyName
che hai appena dichiarato. Non puoi accedere direttamente alla variabile nel file XML. Devi accedervi tramite l'oggetto di binding.
binding.myName = myName
- Potrebbe essere visualizzato un errore perché devi aggiornare l'oggetto di binding dopo aver apportato le 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 di dati anche per il nickname in TextView
.
- Apri
activity_main.xml
. - Nella visualizzazione di testo
nickname_text
, aggiungi una proprietàtext
. Fai riferimento anickname
nella classe di dati, come mostrato di seguito.
android:text="@={myName.nickname}"
- In
ActivityMain
, sostituiscinicknameText.text = nicknameEdit.text.toString()
con il codice per impostare il nickname nella variabilemyName
.
myName?.nickname = nicknameEdit.text.toString()
Una volta impostato il nickname, vuoi che il codice aggiorni la UI con i nuovi dati. Per farlo, devi invalidare tutte le espressioni di binding in modo che vengano ricreate con i dati corretti.
- Aggiungi
invalidateAll()
dopo aver impostato il nickname in modo che l'interfaccia utente venga aggiornata con il valore nell'oggetto di binding aggiornato.
binding.apply {
myName?.nickname = nicknameEdit.text.toString()
invalidateAll()
...
}
- Crea ed esegui la tua app, che dovrebbe funzionare esattamente come prima.
Progetto Android Studio: AboutMeDataBinding
Passaggi per utilizzare il data binding per sostituire le chiamate a findViewById()
:
- Attiva il data binding nella sezione android del file
build.gradle
:dataBinding { enabled = true }
- Utilizza
<layout>
come visualizzazione principale nel layout XML. - Definisci una variabile di binding:
private lateinit var binding: ActivityMainBinding
- Crea un oggetto di associazione in
MainActivity
, sostituendosetContentView
:binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
- Sostituisci le chiamate a
findViewById()
con i riferimenti alla visualizzazione nell'oggetto di binding. Ad esempio:findViewById<Button>(R.id.done_button) ⇒ binding.doneBu
tton
(nell'esempio, il nome della visualizzazione viene generato in formato camel case dalid
della visualizzazione nel file XML).
Passaggi per associare le visualizzazioni ai dati:
- Crea una classe di dati per i tuoi dati.
- Aggiungi un blocco
<data>
all'interno del tag<layout>
. - Definisci un
<variable>
con un nome e un tipo che sia la classe di dati.
<data>
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
</data>
- In
MainActivity
, crea una variabile con un'istanza della classe di dati. Ad esempio:private val myName: MyName = MyName("Aleks Haecky")
- Nell'oggetto di binding, imposta la variabile sulla variabile che hai appena creato:
binding.myName = myName
- Nel file XML, imposta i contenuti della visualizzazione sulla variabile definita nel blocco
<data>
. Utilizza la notazione con il punto per accedere ai dati all'interno della classe di dati.android:text="@={myName.name}"
Corso Udacity:
Documentazione per sviluppatori Android:
- Libreria Data Binding
- Classi di binding generate
- Inizia con il data binding
- Layout ed espressioni di binding
Questa sezione elenca i possibili compiti a casa per gli studenti che seguono questo codelab nell'ambito di un corso guidato da un insegnante. Spetta all'insegnante:
- Assegna i compiti, se richiesto.
- Comunica agli studenti come inviare i compiti.
- Valuta i compiti a casa.
Gli insegnanti possono utilizzare questi suggerimenti nella misura che ritengono opportuna e sono liberi di assegnare qualsiasi altro compito a casa che ritengono appropriato.
Se stai seguendo questo codelab in autonomia, sentiti libero di utilizzare questi compiti per casa 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()
, viene attraversata la gerarchia delle visualizzazioni. findViewById()
viene eseguito sul thread principale o dell'interfaccia utente.- Queste chiamate possono rallentare l'interfaccia utente.
- È meno probabile che la tua app si arresti in modo anomalo.
Domanda 2
Come descriveresti il data binding?
Ad esempio, ecco alcune cose che potresti dire sul data binding:
- L'idea principale del data binding è creare un oggetto che colleghi/mappi/associ due informazioni distanti tra loro in fase di compilazione, in modo da non dover cercare i dati in fase di runtime.
- L'oggetto che mostra questi binding è chiamato oggetto di binding.
- L'oggetto di binding viene creato dal compilatore.
Domanda 3
Quale dei seguenti NON è un vantaggio del data binding?
- Il codice è più breve, più facile da leggere e da gestire.
- Dati e visualizzazioni sono chiaramente separati.
- Il sistema Android attraversa la gerarchia delle visualizzazioni una sola volta per ottenere ogni visualizzazione.
- La chiamata a
findViewById()
genera un errore del compilatore. - Sicurezza dei tipi per accedere alle visualizzazioni.
Domanda 4
Qual è la funzione del tag <layout>
?
- Lo avvolgi intorno alla visualizzazione principale nel layout.
- I binding vengono creati per tutte le visualizzazioni in un layout.
- Indica la visualizzazione di primo livello in un layout XML che utilizza il data binding.
- Puoi utilizzare il tag
<data>
all'interno di un<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:
Per i link ad altri codelab di questo corso, consulta la pagina di destinazione dei codelab di Android Kotlin Fundamentals.