Dieses Codelab ist Teil des Kurses „Grundlagen von Android und Kotlin“. Sie können diesen Kurs am besten nutzen, wenn Sie die Codelabs der Reihe nach durcharbeiten. Alle Codelabs des Kurses sind auf der Landingpage für Codelabs zu den Grundlagen von Android und Kotlin aufgeführt.
Einführung
In früheren Codelabs dieses Kurses haben Sie die Funktion findViewById()
verwendet, um Referenzen zu Ansichten abzurufen. Wenn Ihre App komplexe Ansichtshierarchien hat, ist findViewById()
ressourcenintensiv und verlangsamt die App, da Android die Ansichtshierarchie durchläuft, beginnend mit dem Stamm, bis die gewünschte Ansicht gefunden wird. Glücklicherweise gibt es eine bessere Lösung.
Um Daten in Ansichten festzulegen, haben Sie String-Ressourcen verwendet und die Daten aus der Aktivität festgelegt. Es wäre effizienter, wenn die Ansicht die Daten kennen würde. Glücklicherweise ist das möglich.
In diesem Codelab erfahren Sie, wie Sie die Datenbindung verwenden, um findViewById()
zu vermeiden. Außerdem erfahren Sie, wie Sie mit der Datenbindung direkt über eine Ansicht auf Daten zugreifen.
Was Sie bereits wissen sollten
Sie sollten mit Folgendem vertraut sein:
- Was eine Aktivität ist und wie Sie eine Aktivität mit einem Layout in
onCreate()
einrichten. - Erstellen einer Textansicht und Festlegen des Texts, der in der Textansicht angezeigt wird.
- Mit
findViewById()
eine Referenz auf eine Ansicht abrufen. - Erstellen und Bearbeiten eines einfachen XML-Layouts für eine Ansicht.
Lerninhalte
- So verwenden Sie die Data Binding Library, um ineffiziente Aufrufe von
findViewById()
zu vermeiden. - So greifen Sie direkt über XML auf App-Daten zu.
Aufgaben
- Ändern Sie eine App so, dass sie anstelle von
findViewById()
die Datenbindung verwendet und direkt über die Layout-XML-Dateien auf Daten zugreift.
In diesem Codelab beginnen Sie mit der AboutMe-App und ändern sie so, dass sie Data Binding verwendet. Die App sieht danach genauso aus wie vorher.
Das kann die AboutMe App:
- Wenn der Nutzer die App öffnet, werden ein Name, ein Feld zur Eingabe eines Alias, die Schaltfläche Fertig, ein Sternbild und scrollbarer Text angezeigt.
- Der Nutzer kann einen Alias eingeben und auf die Schaltfläche Fertig tippen. Das bearbeitbare Feld und die Schaltfläche werden durch eine Textansicht ersetzt, in der der eingegebene Alias angezeigt wird.
Sie können den Code verwenden, den Sie im vorherigen Codelab erstellt haben, oder den AboutMeDataBinding-Starter-Code von GitHub herunterladen.
Im Code, den Sie in früheren Codelabs geschrieben haben, wird die Funktion findViewById()
verwendet, um Referenzen auf Ansichten abzurufen.
Jedes Mal, wenn Sie mit findViewById()
nach einer Ansicht suchen, nachdem sie erstellt oder neu erstellt wurde, durchläuft das Android-System die Ansichtshierarchie zur Laufzeit, um sie zu finden. Wenn Ihre App nur wenige Aufrufe hat, ist das kein Problem. In Produktions-Apps kann es jedoch Dutzende von Ansichten in einem Layout geben und selbst bei optimalem Design sind verschachtelte Ansichten nicht zu vermeiden.
Stellen Sie sich ein lineares Layout vor, das eine Scrollansicht mit einer Textansicht enthält. Bei einer großen oder tiefen Ansichtshierarchie kann das Suchen nach einer Ansicht so lange dauern, dass die App für den Nutzer spürbar langsamer wird. Das Zwischenspeichern von Ansichten in Variablen kann helfen, aber Sie müssen trotzdem für jede Ansicht in jedem Namespace eine Variable initialisieren. Bei vielen Aufrufen und mehreren Aktivitäten summiert sich das.
Eine Lösung besteht darin, ein Objekt zu erstellen, das einen Verweis auf jede Ansicht enthält. Dieses Objekt, ein Binding
-Objekt, kann von Ihrer gesamten App verwendet werden. Diese Technik wird als Datenbindung bezeichnet. Nachdem ein Bindungsobjekt für Ihre App erstellt wurde, können Sie über das Bindungsobjekt auf die Ansichten und andere Daten zugreifen, ohne die Ansichtshierarchie durchlaufen oder nach den Daten suchen zu müssen.
Die Datenbindung bietet folgende Vorteile:
- Code, der
findByView()
verwendet, ist kürzer, leichter zu lesen und einfacher zu warten. - Daten und Ansichten sind klar getrennt. Dieser Vorteil der Datenbindung wird später in diesem Kurs immer wichtiger.
- Das Android-System durchläuft die Ansichtshierarchie nur einmal, um jede Ansicht abzurufen. Dies geschieht beim Start der App, nicht zur Laufzeit, wenn der Nutzer mit der App interagiert.
- Sie erhalten Typsicherheit für den Zugriff auf Ansichten. Typsicherheit bedeutet, dass der Compiler Typen während der Kompilierung validiert und einen Fehler ausgibt, wenn Sie versuchen, einer Variablen den falschen Typ zuzuweisen.
In dieser Aufgabe richten Sie die Datenbindung ein und ersetzen Aufrufe von findViewById()
durch Aufrufe des Bindungsobjekts.
Schritt 1: Datenbindung aktivieren
Wenn Sie die Datenbindung verwenden möchten, müssen Sie sie in Ihrer Gradle-Datei aktivieren, da sie standardmäßig nicht aktiviert ist. Das liegt daran, dass die Datenbindung die Kompilierungszeit verlängert und sich auf die Startzeit der App auswirken kann.
- Wenn Sie die AboutMe-App aus einem vorherigen Codelab nicht haben, laden Sie den Code AboutMeDataBinding-Starter von GitHub herunter. Öffnen Sie es in Android Studio.
- Öffnen Sie die Datei
build.gradle (Module: app)
. - Fügen Sie im Abschnitt
android
vor der schließenden geschweiften Klammer einen AbschnittdataBinding
hinzu und setzen Sieenabled
auftrue
.
dataBinding {
enabled = true
}
- Wenn Sie dazu aufgefordert werden, synchronisieren Sie das Projekt. Wenn Sie nicht dazu aufgefordert werden, wählen Sie File > Sync Project with Gradle Files (Datei > Projekt mit Gradle-Dateien synchronisieren) aus.
- Sie können die App ausführen, aber es werden keine Änderungen angezeigt.
Schritt 2: Layoutdatei für die Verwendung mit der Datenbindung ändern
Wenn Sie Datenbindung verwenden möchten, müssen Sie Ihr XML-Layout mit einem <layout>
-Tag umschließen. Dadurch ist die Stammklasse keine Ansichtsgruppe mehr, sondern ein Layout, das Ansichtsgruppen und Ansichten enthält. Das Bindungsobjekt kann dann das Layout und die darin enthaltenen Ansichten kennen.
- Öffnen Sie die Datei
activity_main.xml
. - Wechseln Sie zum Tab Text.
- Fügen Sie
<layout></layout>
als äußerstes Tag um<LinearLayout>
hinzu.
<layout>
<LinearLayout ... >
...
</LinearLayout>
</layout>
- Wählen Sie Code > Code neu formatieren aus, um die Codeeinrückung zu korrigieren.
Die Namespace-Deklarationen für ein Layout müssen sich im äußersten Tag befinden.
- Schneiden Sie die Namespace-Deklarationen aus
<LinearLayout>
aus und fügen Sie sie in das<layout>
-Tag ein. Ihr öffnendes<layout>
-Tag sollte wie unten dargestellt aussehen und das<LinearLayout>
-Tag sollte nur Ansichtseigenschaften enthalten.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
- Erstellen und führen Sie Ihre App aus, um zu prüfen, ob Sie alles richtig gemacht haben.
Schritt 3: Bindungsobjekt in der Hauptaktivität erstellen
Fügen Sie der Hauptaktivität einen Verweis auf das Bindungsobjekt hinzu, damit Sie damit auf Ansichten zugreifen können:
- Öffnen Sie die Datei
MainActivity.kt
. - Erstellen Sie vor
onCreate()
auf der obersten Ebene eine Variable für das Bindungsobjekt. Diese Variable wird üblicherweise alsbinding
bezeichnet.
Der Typ vonbinding
, die KlasseActivityMainBinding
, wird vom Compiler speziell für diese Hauptaktivität erstellt. Der Name wird vom Namen der Layoutdatei abgeleitet, alsoactivity_main + Binding
.
private lateinit var binding: ActivityMainBinding
- Wenn Sie von Android Studio dazu aufgefordert werden, importieren Sie
ActivityMainBinding
. Wenn Sie nicht dazu aufgefordert werden, klicken Sie aufActivityMainBinding
und drücken SieAlt+Enter
(Option+Enter
auf einem Mac), um diese fehlende Klasse zu importieren. Weitere Tastenkombinationen finden Sie hier.
Dieimport
-Anweisung sollte in etwa so aussehen:
import com.example.android.aboutme.databinding.ActivityMainBinding
Als Nächstes ersetzen Sie die aktuelle setContentView()
-Funktion durch eine Anweisung, die Folgendes ausführt:
- Erstellt das Bindungsobjekt.
- Verwendet die Funktion
setContentView()
aus der KlasseDataBindingUtil
, um dasactivity_main
-Layout mit demMainActivity
zu verknüpfen. DiesesetContentView()
-Funktion übernimmt auch die Einrichtung der Datenbindung für die Ansichten.
- Ersetzen Sie in
onCreate()
densetContentView()
-Aufruf durch die folgende Codezeile.
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
- Importieren Sie
DataBindingUtil
.
import androidx.databinding.DataBindingUtil
Schritt 4: Alle Aufrufe von findViewById() durch das Binding-Objekt ersetzen
Sie können jetzt alle Aufrufe von findViewById()
durch Verweise auf die Ansichten im Bindungsobjekt ersetzen. Wenn das Binding-Objekt erstellt wird, generiert der Compiler die Namen der Ansichten im Binding-Objekt aus den IDs der Ansichten im Layout und wandelt sie in CamelCase um. done_button
ist beispielsweise doneButton
im Bindungsobjekt, nickname_edit
wird zu nicknameEdit
und nickname_text
zu nicknameText
.
- Ersetzen Sie in
onCreate()
den Code, derfindViewById()
verwendet, um diedone_button
zu finden, durch Code, der auf die Schaltfläche im Bindungsobjekt verweist.
Ersetzen Sie diesen Code:findViewById<Button>(R.id.
done_button
)
durch:binding.doneButton
Ihr fertiger Code zum Festlegen des Klick-Listeners inonCreate()
sollte so aussehen.
binding.doneButton.setOnClickListener {
addNickname(it)
}
- Wiederholen Sie diesen Schritt für alle Aufrufe von
findViewById()
in der FunktionaddNickname()
.
Ersetzen Sie alle Vorkommen vonfindViewById<
View
>(R.id.
id_view
)
durchbinding.
idView
. Gehen Sie dazu so vor:
- Löschen Sie die Definitionen für die Variablen
editText
undnicknameTextView
sowie die zugehörigen Aufrufe vonfindViewById()
. Das führt zu Fehlern. - Beheben Sie die Fehler, indem Sie die Ansichten
nicknameText
,nicknameEdit
unddoneButton
aus dembinding
-Objekt anstelle der (gelöschten) Variablen abrufen. - Ersetzen Sie
view.visibility
durchbinding.doneButton.visibility
. Durch die Verwendung vonbinding.doneButton
anstelle des übergebenenview
wird der Code einheitlicher.
Das Ergebnis ist der folgende Code:
binding.nicknameText.text = binding.nicknameEdit.text
binding.nicknameEdit.visibility = View.GONE
binding.doneButton.visibility = View.GONE
binding.nicknameText.visibility = View.VISIBLE
- Die Funktionalität bleibt unverändert. Optional können Sie jetzt den Parameter
view
entfernen und alle Verwendungen vonview
in dieser Funktion inbinding.doneButton
ändern.
- Für
nicknameText
ist einString
erforderlich undnicknameEdit.text
ist einEditable
. Wenn Sie die Datenbindung verwenden, müssen SieEditable
explizit inString
konvertieren.
binding.nicknameText.text = binding.nicknameEdit.text.toString()
- Sie können die ausgegrauten Importe löschen.
- Verwenden Sie
apply{}
, um die Funktion in Kotlin zu konvertieren.
binding.apply {
nicknameText.text = nicknameEdit.text.toString()
nicknameEdit.visibility = View.GONE
doneButton.visibility = View.GONE
nicknameText.visibility = View.VISIBLE
}
- Erstellen Sie Ihre App und führen Sie sie aus. Sie sollte genauso aussehen und funktionieren wie zuvor.
Mit der Datenbindung können Sie eine Datenklasse direkt für eine Ansicht verfügbar machen. Diese Technik vereinfacht den Code und ist äußerst nützlich für komplexere Fälle.
In diesem Beispiel erstellen Sie anstelle von String-Ressourcen eine Datenklasse für den Namen und den Alias. Sie stellen die Datenklasse über die Datenbindung für die Ansicht zur Verfügung.
Schritt 1: Datenklasse „MyName“ erstellen
- Öffnen Sie in Android Studio die Datei
MyName.kt
im Verzeichnisjava
. Wenn Sie diese Datei nicht haben, erstellen Sie eine neue Kotlin-Datei und nennen Sie sieMyName.kt
. - Definieren Sie eine Datenklasse für den Namen und den Spitznamen. Verwenden Sie leere Strings als Standardwerte.
data class MyName(var name: String = "", var nickname: String = "")
Schritt 2: Daten zum Layout hinzufügen
In der Datei activity_main.xml
wird der Name derzeit in einem TextView
aus einer String-Ressource festgelegt. Sie müssen den Verweis auf den Namen durch einen Verweis auf Daten in der Datenklasse ersetzen.
- Öffnen Sie
activity_main.xml
auf dem Tab Text. - Fügen Sie oben im Layout zwischen den Tags
<layout>
und<LinearLayout>
ein<data></data>
-Tag ein. Hier verbinden Sie die Ansicht mit den Daten.
<data>
</data>
Innerhalb der Datentags können Sie benannte Variablen deklarieren, die einen Verweis auf eine Klasse enthalten.
- Fügen Sie im Tag
<data>
ein Tag<variable>
hinzu. - Fügen Sie einen
name
-Parameter hinzu, um der Variablen den Namen"myName"
zu geben. Fügen Sie einentype
-Parameter hinzu und legen Sie den Typ auf den vollständig qualifizierten Namen derMyName
-Datenklasse fest (Paketname + Variablenname).
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
Anstatt die String-Ressource für den Namen zu verwenden, können Sie jetzt auf die Variable myName
verweisen.
- Ersetzen Sie
android:text="@string/name"
durch den folgenden Code.
@={}
ist eine Anweisung zum Abrufen der Daten, auf die in den geschweiften Klammern verwiesen wird.
myName
verweist auf die zuvor definierte Variable myName
, die auf die Datenklasse myName
verweist und die Eigenschaft name
aus der Klasse abruft.
android:text="@={myName.name}"
Schritt 3: Daten erstellen
Sie haben jetzt einen Verweis auf die Daten in Ihrer Layoutdatei. Als Nächstes erstellen Sie die eigentlichen Daten.
- Öffnen Sie die Datei
MainActivity.kt
. - Erstellen Sie über
onCreate()
eine private Variable, die gemäß Konvention ebenfallsmyName
heißt. Weisen Sie der Variablen eine Instanz der DatenklasseMyName
zu und übergeben Sie den Namen.
private val myName: MyName = MyName("Aleks Haecky")
- Legen Sie in
onCreate()
den Wert der VariablenmyName
in der Layoutdatei auf den Wert der VariablenmyName
fest, die Sie gerade deklariert haben. Sie können nicht direkt in der XML-Datei auf die Variable zugreifen. Sie müssen über das Bindungsobjekt darauf zugreifen.
binding.myName = myName
- Möglicherweise wird ein Fehler angezeigt, da Sie das Bindungsobjekt nach Änderungen aktualisieren müssen. Erstellen Sie Ihre App. Der Fehler sollte dann nicht mehr auftreten.
Schritt 4: Datenklasse für den Aliasnamen in der TextView verwenden
Im letzten Schritt verwenden Sie die Datenklasse auch für den Alias in TextView
.
- Öffnen Sie
activity_main.xml
. - Fügen Sie in der Textansicht
nickname_text
einetext
-Eigenschaft hinzu. Verweisen Sie wie unten gezeigt aufnickname
in der Datenklasse.
android:text="@={myName.nickname}"
- Ersetzen Sie in
ActivityMain
nicknameText.text = nicknameEdit.text.toString()
durch Code, um den Alias in der VariablenmyName
festzulegen.
myName?.nickname = nicknameEdit.text.toString()
Nachdem der Alias festgelegt wurde, soll die Benutzeroberfläche mit den neuen Daten aktualisiert werden. Dazu müssen Sie alle Bindungsausdrücke ungültig machen, damit sie mit den richtigen Daten neu erstellt werden.
- Fügen Sie
invalidateAll()
hinzu, nachdem Sie den Alias festgelegt haben, damit die Benutzeroberfläche mit dem Wert im aktualisierten Bindungsobjekt aktualisiert wird.
binding.apply {
myName?.nickname = nicknameEdit.text.toString()
invalidateAll()
...
}
- Erstellen und führen Sie Ihre App aus. Sie sollte genau wie zuvor funktionieren.
Android Studio-Projekt: AboutMeDataBinding
So ersetzen Sie Aufrufe von findViewById()
durch die Datenbindung:
- Aktivieren Sie die Datenbindung im Android-Abschnitt der Datei
build.gradle
:dataBinding { enabled = true }
- Verwenden Sie
<layout>
als Stammansicht in Ihrem XML-Layout. - Bindungsvariable definieren:
private lateinit var binding: ActivityMainBinding
- Erstellen Sie ein Bindungsobjekt in
MainActivity
und ersetzen SiesetContentView
:binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
- Ersetzen Sie Aufrufe von
findViewById()
durch Verweise auf die Ansicht im Bindungsobjekt. Beispiel:findViewById<Button>(R.id.done_button) ⇒ binding.doneBu
tton
(Im Beispiel wird der Name der Ansicht im CamelCase-Format aus demid
der Ansicht im XML-Code generiert.)
So binden Sie Ansichten an Daten:
- Erstellen Sie eine Datenklasse für Ihre Daten.
- Fügen Sie dem
<layout>
-Tag einen<data>
-Block hinzu. - Definieren Sie eine
<variable>
mit einem Namen und einem Typ, der die Datenklasse ist.
<data>
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
</data>
- Erstellen Sie in
MainActivity
eine Variable mit einer Instanz der Datenklasse. Beispiel:private val myName: MyName = MyName("Aleks Haecky")
- Legen Sie im Bindungsobjekt die Variable auf die Variable fest, die Sie gerade erstellt haben:
binding.myName = myName
- Legen Sie in der XML-Datei den Inhalt der Ansicht auf die Variable fest, die Sie im Block
<data>
definiert haben. Verwenden Sie die Punktnotation, um auf die Daten in der Datenklasse zuzugreifen.android:text="@={myName.name}"
Udacity-Kurs:
Android-Entwicklerdokumentation:
- Data Binding Library
- Generierte Bindungsklassen
- Erste Schritte mit der Datenbindung
- Layouts und Bindungsausdrücke
In diesem Abschnitt werden mögliche Hausaufgaben für Schüler und Studenten aufgeführt, die dieses Codelab im Rahmen eines von einem Kursleiter geleiteten Kurses durcharbeiten. Es liegt in der Verantwortung des Kursleiters, Folgendes zu tun:
- Weisen Sie bei Bedarf Aufgaben zu.
- Teilen Sie den Schülern/Studenten mit, wie sie Hausaufgaben abgeben können.
- Benoten Sie die Hausaufgaben.
Lehrkräfte können diese Vorschläge nach Belieben nutzen und auch andere Hausaufgaben zuweisen, die sie für angemessen halten.
Wenn Sie dieses Codelab selbst durcharbeiten, können Sie mit diesen Hausaufgaben Ihr Wissen testen.
Beantworten Sie diese Fragen
Frage 1
Warum sollten explizite und implizite Aufrufe von findViewById()
minimiert werden?
- Bei jedem Aufruf von
findViewById()
wird die Ansichtshierarchie durchlaufen. findViewById()
wird im Haupt- oder UI-Thread ausgeführt.- Diese Aufrufe können die Benutzeroberfläche verlangsamen.
- Ihre App stürzt seltener ab.
Frage 2
Wie würden Sie die Datenbindung beschreiben?
Hier sind einige Beispiele für Aussagen, die Sie über die Datenbindung machen könnten:
- Die Idee hinter der Datenbindung besteht darin, zur Kompilierzeit ein Objekt zu erstellen, das zwei weit voneinander entfernte Informationen miteinander verbindet/zuordnet/bindet, sodass Sie zur Laufzeit nicht nach den Daten suchen müssen.
- Das Objekt, das diese Bindungen für Sie verfügbar macht, wird als Bindungsobjekt bezeichnet.
- Das Bindungsobjekt wird vom Compiler erstellt.
Frage 3
Welche der folgenden Optionen ist KEIN Vorteil der Datenbindung?
- Der Code ist kürzer, leichter zu lesen und einfacher zu warten.
- Daten und Ansichten sind klar getrennt.
- Das Android-System durchläuft die Ansichtshierarchie nur einmal, um jede Ansicht abzurufen.
- Der Aufruf von
findViewById()
führt zu einem Compilerfehler. - Typsicherheit für den Zugriff auf Ansichten.
Frage 4
Wozu dient das <layout>
-Tag?
- Sie umschließen damit die Stammansicht im Layout.
- Für alle Ansichten in einem Layout werden Bindungen erstellt.
- Sie gibt die Ansicht der obersten Ebene in einem XML-Layout an, das die Datenbindung verwendet.
- Mit dem
<data>
-Tag innerhalb eines<layout>
-Tags können Sie eine Variable an eine Datenklasse binden.
Frage 5
Wie werden gebundene Daten im XML-Layout richtig referenziert?
android:text="@={myDataClass.property}"
android:text="@={myDataClass}"
android:text="@={myDataClass.property.toString()}"
android:text="@={myDataClass.bound_data.property}"
Nächste Lektion starten:
Links zu anderen Codelabs in diesem Kurs finden Sie auf der Landingpage für Android Kotlin Fundamentals-Codelabs.