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
Im vorherigen Codelab haben Sie die App „TrackMySleepQuality“ so aktualisiert, dass Daten zur Schlafqualität in einem RecyclerView
angezeigt werden. Die Techniken, die Sie beim Erstellen Ihres ersten RecyclerView
gelernt haben, reichen für die meisten RecyclerViews
aus, in denen einfache, nicht zu lange Listen angezeigt werden. Es gibt jedoch eine Reihe von Techniken, mit denen RecyclerView
für große Listen effizienter wird und mit denen sich Ihr Code für komplexe Listen und Tabellen leichter warten und erweitern lässt.
In diesem Codelab bauen Sie auf der Sleep-Tracker-App aus dem vorherigen Codelab auf. Sie lernen eine effektivere Methode zum Aktualisieren der Liste der Schlafdaten kennen und erfahren, wie Sie die Datenbindung mit RecyclerView
verwenden. Wenn Sie die App aus dem vorherigen Codelab nicht haben, können Sie den Startcode für dieses Codelab herunterladen.
Was Sie bereits wissen sollten
- Eine einfache Benutzeroberfläche mit einer Aktivität, Fragmenten und Ansichten erstellen
- Zwischen Fragmenten wechseln und
safeArgs
verwenden, um Daten zwischen Fragmenten zu übergeben. - Modelle, Modell-Factories, Transformationen und
LiveData
sowie deren Beobachter ansehen - So erstellen Sie eine
Room
-Datenbank, ein DAO und definieren Entitäten. - Verwendung von Coroutinen für Datenbanken und andere lang andauernde Aufgaben.
- So implementieren Sie ein einfaches
RecyclerView
mit einemAdapter
, einemViewHolder
und einem Elementlayout.
Lerninhalte
- So verwenden Sie
DiffUtil
, um eine vonRecyclerView
angezeigte Liste effizient zu aktualisieren. - So verwenden Sie die Datenbindung mit
RecyclerView
. - Bindungsadapter zum Transformieren von Daten verwenden
Aufgaben
- In diesem Codelab bauen Sie auf der App „TrackMySleepQuality“ aus dem vorherigen Codelab dieser Reihe auf.
- Aktualisieren Sie
SleepNightAdapter
, um die Liste effizient mitDiffUtil
zu aktualisieren. - Implementieren Sie die Datenbindung für
RecyclerView
und verwenden Sie Bindungsadapter, um die Daten zu transformieren.
Die Schlaftracking-App hat zwei Bildschirme, die durch Fragmente dargestellt werden, wie in der Abbildung unten zu sehen ist.
Auf dem ersten Bildschirm, der links angezeigt wird, befinden sich Schaltflächen zum Starten und Beenden des Trackings. Auf dem Display werden einige der Schlafdaten des Nutzers angezeigt. Mit der Schaltfläche Löschen werden alle Daten, die die App für den Nutzer erhoben hat, dauerhaft gelöscht. Auf dem zweiten Bildschirm rechts können Sie eine Bewertung der Schlafqualität auswählen.
Diese App ist so konzipiert, dass sie einen UI-Controller, ViewModel
und LiveData
sowie eine Room
-Datenbank zum Speichern von Schlafdaten verwendet.
Die Schlafdaten werden in einem RecyclerView
angezeigt. In diesem Codelab erstellen Sie den DiffUtil
- und den Data Binding-Teil für RecyclerView
. Nach diesem Codelab sieht Ihre App genauso aus wie vorher, ist aber effizienter und lässt sich leichter skalieren und warten.
Sie können die SleepTracker-App aus dem vorherigen Codelab weiter verwenden oder die RecyclerViewDiffUtilDataBinding-Starter-App von GitHub herunterladen.
- Laden Sie bei Bedarf die RecyclerViewDiffUtilDataBinding-Starter-App von GitHub herunter und öffnen Sie das Projekt in Android Studio.
- Starten Sie die App.
- Öffnen Sie die Datei
SleepNightAdapter.kt
. - Sehen Sie sich den Code an, um sich mit der Struktur der App vertraut zu machen. Das Diagramm unten fasst zusammen, wie
RecyclerView
mit dem Adaptermuster verwendet wird, um dem Nutzer Schlafdauerdaten anzuzeigen.
- Die App erstellt aus Nutzereingaben eine Liste von
SleepNight
-Objekten. JedesSleepNight
-Objekt steht für eine einzelne Nacht mit Schlaf, ihre Dauer und Qualität. - Mit
SleepNightAdapter
wird die Liste derSleepNight
-Objekte in ein Format umgewandelt, das vonRecyclerView
verwendet und angezeigt werden kann. - Der
SleepNightAdapter
-Adapter erzeugtViewHolders
, die die Ansichten, Daten und Metainformationen für die RecyclerView enthalten, um die Daten darzustellen. RecyclerView
verwendetSleepNightAdapter
, um die Anzahl der anzuzeigenden Elemente (getItemCount()
) zu ermitteln.RecyclerView
verwendetonCreateViewHolder()
undonBindViewHolder()
, um ViewHolders abzurufen, die an Daten gebunden sind, die angezeigt werden sollen.
Die Methode „notifyDataSetChanged()“ ist ineffizient
Damit RecyclerView
weiß, dass sich ein Element in der Liste geändert hat und aktualisiert werden muss, wird im aktuellen Code notifyDataSetChanged()
in SleepNightAdapter
aufgerufen, wie unten gezeigt.
var data = listOf<SleepNight>()
set(value) {
field = value
notifyDataSetChanged()
}
notifyDataSetChanged()
teilt RecyclerView
jedoch mit, dass die gesamte Liste möglicherweise ungültig ist. Daher werden alle Elemente in der Liste neu gebunden und neu gezeichnet, auch Elemente, die nicht auf dem Bildschirm sichtbar sind.RecyclerView
Das ist viel unnötige Arbeit. Bei großen oder komplexen Listen kann dieser Vorgang so lange dauern, dass das Display flackert oder ruckelt, wenn der Nutzer durch die Liste scrollt.
Um dieses Problem zu beheben, können Sie RecyclerView
genau mitteilen, was sich geändert hat. RecyclerView
kann dann nur die Ansichten aktualisieren, die sich auf dem Bildschirm geändert haben.
RecyclerView
bietet eine umfangreiche API zum Aktualisieren einzelner Elemente. Mit notifyItemChanged()
können Sie RecyclerView
mitteilen, dass sich ein Element geändert hat. Ähnliche Funktionen gibt es für Elemente, die hinzugefügt, entfernt oder verschoben werden. Sie könnten alles manuell erledigen, aber das wäre nicht einfach und würde wahrscheinlich viel Code erfordern.
Glücklicherweise gibt es eine bessere Lösung.
DiffUtil ist effizient und nimmt Ihnen die Arbeit ab
RecyclerView
hat eine Klasse namens DiffUtil
, mit der die Unterschiede zwischen zwei Listen berechnet werden. DiffUtil
vergleicht eine alte und eine neue Liste und ermittelt die Unterschiede. Es werden Elemente gefunden, die hinzugefügt, entfernt oder geändert wurden. Dazu wird ein Algorithmus namens Eugene W. Myers-Differenzalgorithmus, um die Mindestanzahl der Änderungen zu ermitteln, die an der alten Liste vorgenommen werden müssen, um die neue Liste zu erstellen.
Sobald DiffUtil
herausgefunden hat, was sich geändert hat, kann RecyclerView
diese Informationen verwenden, um nur die Elemente zu aktualisieren, die geändert, hinzugefügt, entfernt oder verschoben wurden. Das ist viel effizienter, als die gesamte Liste neu zu erstellen.
In dieser Aufgabe aktualisieren Sie SleepNightAdapter
, um DiffUtil
zu verwenden und RecyclerView
für Änderungen an den Daten zu optimieren.
Schritt 1: SleepNightDiffCallback implementieren
Wenn Sie die Funktionalität der Klasse DiffUtil
verwenden möchten, erweitern Sie DiffUtil.ItemCallback
.
- Öffnen Sie
SleepNightAdapter.kt
. - Erstellen Sie unter der vollständigen Klassendefinition für
SleepNightAdapter
eine neue Klasse der obersten Ebene mit dem NamenSleepNightDiffCallback
, dieDiffUtil.ItemCallback
erweitert. Übergeben SieSleepNight
als generischen Parameter.
class SleepNightDiffCallback : DiffUtil.ItemCallback<SleepNight>() {
}
- Setzen Sie den Cursor auf den Klassennamen
SleepNightDiffCallback
. - Drücke
Alt+Enter
(Option+Enter
auf dem Mac) und wähle Mitglieder implementieren aus. - Wählen Sie im daraufhin geöffneten Dialogfeld die Methoden
areItemsTheSame()
undareContentsTheSame()
aus, indem Sie bei gedrückter Umschalttaste auf die Methoden klicken, und klicken Sie dann auf OK.
Dadurch werden inSleepNightDiffCallback
Stubs für die beiden Methoden generiert, wie unten dargestellt.DiffUtil
verwendet diese beiden Methoden, um herauszufinden, wie sich die Liste und die Elemente geändert haben.
override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
- Ersetzen Sie in
areItemsTheSame()
dieTODO
durch Code, der prüft, ob die beiden übergebenenSleepNight
-ElementeoldItem
undnewItem
identisch sind. Wenn die Elemente denselbennightId
haben, handelt es sich um dasselbe Element. Gib alsotrue
zurück. Andernfalls wirdfalse
zurückgegeben.DiffUtil
verwendet diesen Test, um festzustellen, ob ein Element hinzugefügt, entfernt oder verschoben wurde.
override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
return oldItem.nightId == newItem.nightId
}
- Prüfen Sie in
areContentsTheSame()
, oboldItem
undnewItem
dieselben Daten enthalten, d. h., ob sie gleich sind. Bei dieser Gleichheitsprüfung werden alle Felder geprüft, daSleepNight
eine Datenklasse ist.Data
-Klassen definieren automatischequals
und einige andere Methoden für Sie. Wenn es Unterschiede zwischenoldItem
undnewItem
gibt, wirdDiffUtil
durch diesen Code darüber informiert, dass das Element aktualisiert wurde.
override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
return oldItem == newItem
}
Es ist ein gängiges Muster, eine RecyclerView
zu verwenden, um eine Liste anzuzeigen, die sich ändert. RecyclerView
bietet eine Adapterklasse, ListAdapter
, mit der Sie einen RecyclerView
-Adapter erstellen können, der auf einer Liste basiert.
ListAdapter
verfolgt die Liste für Sie und benachrichtigt den Adapter, wenn die Liste aktualisiert wird.
Schritt 1: Adapter so ändern, dass er ListAdapter erweitert
- Ändern Sie in der Datei
SleepNightAdapter.kt
die Klassensignatur vonSleepNightAdapter
, sodass sieListAdapter
erweitert. - Importieren Sie bei Aufforderung
androidx.recyclerview.widget.ListAdapter
. - Fügen Sie
SleepNight
als erstes Argument zuListAdapter
vorSleepNightAdapter.ViewHolder
hinzu. - Fügen Sie
SleepNightDiffCallback()
als Parameter zum Konstruktor hinzu.ListAdapter
verwendet diese Informationen, um herauszufinden, was sich in der Liste geändert hat. Die fertigeSleepNightAdapter
-Klassensignatur sollte so aussehen:
class SleepNightAdapter : ListAdapter<SleepNight, SleepNightAdapter.ViewHolder>(SleepNightDiffCallback()) {
- Löschen Sie in der Klasse
SleepNightAdapter
das Felddata
, einschließlich des Setters. Sie benötigen sie nicht mehr, daListAdapter
die Liste für Sie im Blick behält. - Löschen Sie die Überschreibung von
getItemCount()
, daListAdapter
diese Methode für Sie implementiert. - Um den Fehler in
onBindViewHolder()
zu beheben, ändern Sie die Variableitem
. Rufen Sie anstelle vondata
zum Abrufen einesitem
die MethodegetItem(position)
auf, die vonListAdapter
bereitgestellt wird.
val item = getItem(position)
Schritt 2: Mit submitList() die Liste auf dem neuesten Stand halten
Ihr Code muss ListAdapter
mitteilen, wann eine geänderte Liste verfügbar ist. ListAdapter
bietet eine Methode namens submitList()
, um ListAdapter
mitzuteilen, dass eine neue Version der Liste verfügbar ist. Wenn diese Methode aufgerufen wird, vergleicht ListAdapter
die neue Liste mit der alten und erkennt Elemente, die hinzugefügt, entfernt, verschoben oder geändert wurden. Anschließend aktualisiert ListAdapter
die von RecyclerView
angezeigten Elemente.
- Öffnen Sie
SleepTrackerFragment.kt
. - Suchen Sie in
onCreateView()
im Observer fürsleepTrackerViewModel
nach dem Fehler, in dem auf die gelöschte Variabledata
verwiesen wird. - Ersetzen Sie
adapter.data = it
durch einen Aufruf vonadapter.submitList(it)
. Der aktualisierte Code ist unten zu sehen.
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
it?.let {
adapter.submitList(it)
}
})
- Führen Sie Ihre App aus. Sie wird schneller ausgeführt, was bei einer kleinen Liste möglicherweise nicht auffällt.
In dieser Aufgabe verwenden Sie dieselbe Technik wie in früheren Codelabs, um die Datenbindung einzurichten, und entfernen Aufrufe von findViewById()
.
Schritt 1: Datenbindung zur Layoutdatei hinzufügen
- Öffnen Sie die Layoutdatei
list_item_sleep_night.xml
auf dem Tab Text. - Setzen Sie den Cursor auf das Tag
ConstraintLayout
und drücken SieAlt+Enter
(Option+Enter
auf einem Mac). Das Intention-Menü (das Menü für schnelle Korrekturen) wird geöffnet. - Wählen Sie In Layout für die Datenbindung konvertieren aus. Dadurch wird das Layout in
<layout>
eingeschlossen und ein<data>
-Tag eingefügt. - Scrollen Sie bei Bedarf wieder nach oben und deklarieren Sie innerhalb des
<data>
-Tags eine Variable mit dem Namensleep
. - Machen Sie
type
zum vollständig qualifizierten Namen vonSleepNight
,com.example.android.trackmysleepquality.database.SleepNight
. Das fertige<data>
-Tag sollte so aussehen:
<data>
<variable
name="sleep"
type="com.example.android.trackmysleepquality.database.SleepNight"/>
</data>
- Wenn Sie die Erstellung des
Binding
-Objekts erzwingen möchten, wählen Sie Build > Clean Project (Erstellen > Projekt bereinigen) und dann Build > Rebuild Project (Erstellen > Projekt neu erstellen) aus. Wenn Sie weiterhin Probleme haben, wählen Sie Datei > Caches ungültig machen / Neu starten aus. DasListItemSleepNightBinding
-Bindungsobjekt wird zusammen mit dem zugehörigen Code den generierten Dateien des Projekts hinzugefügt.
Schritt 2: Elementlayout mithilfe der Datenbindung aufblähen
- Öffnen Sie
SleepNightAdapter.kt
. - Suchen Sie in der Klasse
ViewHolder
nach der Methodefrom()
. - Löschen Sie die Deklaration der Variablen
view
.
Code zum Löschen:
val view = layoutInflater
.inflate(R.layout.list_item_sleep_night, parent, false)
- Definieren Sie dort, wo sich die Variable
view
befand, eine neue Variable namensbinding
, die dasListItemSleepNightBinding
-Bindungsobjekt aufbläht, wie unten dargestellt. Importieren Sie das Binding-Objekt.
val binding =
ListItemSleepNightBinding.inflate(layoutInflater, parent, false)
- Geben Sie am Ende der Funktion anstelle von
view
binding
zurück.
return ViewHolder(binding)
- Um den Fehler zu beheben, bewegen Sie den Cursor auf das Wort
binding
. Drücken SieAlt+Enter
(Option+Enter
auf einem Mac), um das Intention-Menü zu öffnen.
- Wählen Sie Change parameter 'itemView' type of primary constructor of class 'ViewHolder' to 'ListItemSleepNightBinding' (Ändere den Parametertyp „itemView“ des primären Konstruktors der Klasse „ViewHolder“ in „ListItemSleepNightBinding“) aus. Dadurch wird der Parametertyp der Klasse
ViewHolder
aktualisiert.
- Scrollen Sie nach oben zur Klassendefinition von
ViewHolder
, um die Änderung an der Signatur zu sehen. Sie sehen einen Fehler füritemView
, weil SieitemView
in der Methodefrom()
inbinding
geändert haben.
Klicken Sie in der KlassendefinitionViewHolder
mit der rechten Maustaste auf eine der Instanzen vonitemView
und wählen Sie Refactor > Rename aus. Ändern Sie den Namen inbinding
. - Stellen Sie dem Konstruktorparameter
binding
das Präfixval
voran, um ihn zu einer Property zu machen. - Ändern Sie im Aufruf der übergeordneten Klasse
RecyclerView.ViewHolder
den Parameter vonbinding
zubinding.root
. Sie müssen einView
übergeben.binding.root
ist das Stamm-ConstraintLayout
in Ihrem Artikellayout. - Ihre fertige Klassendeklaration sollte so aussehen:
class ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root){
Außerdem wird ein Fehler für die Aufrufe von findViewById()
angezeigt. Diesen beheben Sie als Nächstes.
Schritt 3: findViewById() ersetzen
Sie können jetzt die Attribute sleepLength
, quality
und qualityImage
aktualisieren, um das Objekt binding
anstelle von findViewById()
zu verwenden.
- Ändern Sie die Initialisierungen von
sleepLength
,qualityString
undqualityImage
, sodass die Ansichten desbinding
-Objekts verwendet werden, wie unten gezeigt. Danach sollten keine Fehler mehr in Ihrem Code angezeigt werden.
val sleepLength: TextView = binding.sleepLength
val quality: TextView = binding.qualityString
val qualityImage: ImageView = binding.qualityImage
Wenn das Bindungsobjekt vorhanden ist, müssen Sie die Attribute sleepLength
, quality
und qualityImage
nicht mehr definieren. DataBinding
speichert die Suchvorgänge im Cache, sodass diese Eigenschaften nicht deklariert werden müssen.
- Klicken Sie mit der rechten Maustaste auf die Attributnamen
sleepLength
,quality
undqualityImage
. Wählen Sie Refactor > Inline aus oder drücken SieControl+Command+N
(Option+Command+N
auf einem Mac). - Führen Sie Ihre App aus. Wenn Fehler auftreten, müssen Sie Ihr Projekt möglicherweise bereinigen und neu erstellen.
In dieser Aufgabe aktualisieren Sie Ihre App, um die Datenbindung mit Bindungsadaptern zu verwenden, um die Daten in Ihren Ansichten festzulegen.
In einem früheren Codelab haben Sie die Klasse Transformations
verwendet, um LiveData
zu übernehmen und formatierte Strings zu generieren, die in Textansichten angezeigt werden. Wenn Sie jedoch verschiedene oder komplexe Typen binden müssen, können Sie Bindungsadapter bereitstellen, damit die Datenbindung diese Typen verwenden kann. Binding-Adapter nehmen Ihre Daten entgegen und passen sie so an, dass sie für die Datenbindung verwendet werden können, um eine Ansicht zu binden, z. B. Text oder ein Bild.
Sie implementieren drei Binding-Adapter, einen für das Qualitätsbild und einen für jedes Textfeld. Zusammenfassend lässt sich sagen, dass Sie zum Deklarieren eines Binding-Adapters eine Methode definieren, die ein Element und eine Ansicht akzeptiert, und sie mit @BindingAdapter
annotieren. Im Methodenkörper implementieren Sie die Transformation. In Kotlin können Sie einen Binding-Adapter als Erweiterungsfunktion für die Ansichtsklasse schreiben, die die Daten empfängt.
Schritt 1: Bindungsadapter erstellen
Beachten Sie, dass Sie in diesem Schritt eine Reihe von Klassen importieren müssen. Diese werden nicht einzeln aufgeführt.
- Öffnen Sie
SleepNightAdapater.kt
. - Suchen Sie in der Klasse
ViewHolder
nach der Methodebind()
und sehen Sie sich noch einmal an, was diese Methode macht. Sie nehmen den Code, mit dem die Werte fürbinding.sleepLength
,binding.quality
undbinding.qualityImage
berechnet werden, und verwenden ihn stattdessen im Adapter. Lassen Sie den Code vorerst so, wie er ist. Sie verschieben ihn in einem späteren Schritt. - Erstellen Sie im Paket
sleeptracker
eine Datei mit dem NamenBindingUtils.kt
und öffnen Sie sie. - Deklarieren Sie eine Erweiterungsfunktion für
TextView
mit dem NamensetSleepDurationFormatted
und übergeben Sie eineSleepNight
. Diese Funktion ist Ihr Adapter zum Berechnen und Formatieren der Schlafdauer.
fun TextView.setSleepDurationFormatted(item: SleepNight) {}
- Binden Sie die Daten im Text von
setSleepDurationFormatted
an die Ansicht, wie Sie es inViewHolder.bind()
getan haben. Rufen SieconvertDurationToFormatted()
auf und legen Sie dann dietext
vonTextView
auf den formatierten Text fest. Da es sich um eine Erweiterungsfunktion fürTextView
handelt, können Sie direkt auf das Attributtext
zugreifen.
text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, context.resources)
- Um die Datenbindung über diesen Bindungsadapter zu informieren, annotieren Sie die Funktion mit
@BindingAdapter
. - Diese Funktion ist der Adapter für das Attribut
sleepDurationFormatted
. Übergeben SiesleepDurationFormatted
also als Argument an@BindingAdapter
.
@BindingAdapter("sleepDurationFormatted")
- Der zweite Adapter legt die Schlafqualität basierend auf dem Wert in einem
SleepNight
-Objekt fest. Erstellen Sie eine Erweiterungsfunktion mit dem NamensetSleepQualityString()
fürTextView
und übergeben Sie eineSleepNight
. - Binden Sie die Daten im Text an die Ansicht, wie Sie es in
ViewHolder.bind()
getan haben. RufeconvertNumericQualityToString
auf und legetext
fest. - Kommentieren Sie die Funktion mit
@BindingAdapter("sleepQualityString")
.
@BindingAdapter("sleepQualityString")
fun TextView.setSleepQualityString(item: SleepNight) {
text = convertNumericQualityToString(item.sleepQuality, context.resources)
}
- Der dritte Binding-Adapter legt das Bild in einer Image-Ansicht fest. Erstellen Sie die Erweiterungsfunktion für
ImageView
, rufen SiesetSleepImage
auf und verwenden Sie den Code ausViewHolder.bind()
, wie unten gezeigt.
@BindingAdapter("sleepImage")
fun ImageView.setSleepImage(item: SleepNight) {
setImageResource(when (item.sleepQuality) {
0 -> R.drawable.ic_sleep_0
1 -> R.drawable.ic_sleep_1
2 -> R.drawable.ic_sleep_2
3 -> R.drawable.ic_sleep_3
4 -> R.drawable.ic_sleep_4
5 -> R.drawable.ic_sleep_5
else -> R.drawable.ic_sleep_active
})
}
Schritt 2: SleepNightAdapter aktualisieren
- Öffnen Sie
SleepNightAdapter.kt
. - Löschen Sie alles in der
bind()
-Methode, da Sie jetzt die Datenbindung und Ihre neuen Adapter verwenden können, um diese Aufgabe zu erledigen.
fun bind(item: SleepNight) {
}
- Weisen Sie in
bind()
den Schlafitem
zu, da Sie das Bindungsobjekt über Ihren neuenSleepNight
informieren müssen.
binding.sleep = item
- Fügen Sie darunter
binding.executePendingBindings()
ein. Dieser Aufruf ist eine Optimierung, mit der die Datenbindung aufgefordert wird, alle ausstehenden Bindungen sofort auszuführen. Es ist immer eine gute Idee,executePendingBindings()
aufzurufen, wenn Sie Bindungsadapter in einemRecyclerView
verwenden, da dies die Größenanpassung der Ansichten leicht beschleunigen kann.
binding.executePendingBindings()
Schritt 3: Bindungen zum XML-Layout hinzufügen
- Öffnen Sie
list_item_sleep_night.xml
. - Fügen Sie im
ImageView
einapp
-Attribut mit demselben Namen wie der Binding-Adapter hinzu, der das Bild festlegt. Übergeben Sie die Variablesleep
, wie unten gezeigt.
Diese Eigenschaft stellt über den Adapter die Verbindung zwischen der Ansicht und dem Bindungsobjekt her. Immer wenn aufsleepImage
verwiesen wird, werden die Daten ausSleepNight
vom Adapter angepasst.
app:sleepImage="@{sleep}"
- Wiederholen Sie diesen Schritt für die Textansichten
sleep_length
undquality_string
. Immer wenn aufsleepDurationFormatted
odersleepQualityString
verwiesen wird, passen die Adapter die Daten ausSleepNight
an.
app:sleepDurationFormatted="@{sleep}"
app:sleepQualityString="@{sleep}"
- Führen Sie Ihre App aus. Sie funktioniert genau wie zuvor. Die Binding-Adapter übernehmen die gesamte Formatierung und Aktualisierung der Ansichten, wenn sich die Daten ändern. Das vereinfacht
ViewHolder
und sorgt für eine viel bessere Struktur des Codes als zuvor.
Du hast in den letzten Übungen immer dieselbe Liste angezeigt. Das ist so gewollt, um zu zeigen, dass die Adapter
-Schnittstelle viele verschiedene Möglichkeiten bietet, Ihren Code zu strukturieren. Je komplexer Ihr Code ist, desto wichtiger ist es, ihn gut zu strukturieren. In Produktions-Apps werden diese und andere Muster mit RecyclerView
verwendet. Alle Muster funktionieren und haben ihre Vorteile. Welche Sie auswählen, hängt davon ab, was Sie entwickeln.
Glückwunsch! Sie sind auf dem besten Weg, RecyclerView
auf Android zu beherrschen.
Android Studio-Projekt: RecyclerViewDiffUtilDataBinding.
DiffUtil
:
RecyclerView
hat eine Klasse namensDiffUtil
, mit der die Unterschiede zwischen zwei Listen berechnet werden.DiffUtil
hat eine Klasse namensItemCallBack
, die Sie erweitern, um den Unterschied zwischen zwei Listen zu ermitteln.- In der
ItemCallback
-Klasse müssen Sie die MethodenareItemsTheSame()
undareContentsTheSame()
überschreiben.
ListAdapter
:
- Wenn Sie eine kostenlose Listenverwaltung benötigen, können Sie anstelle von
RecyclerView.Adapter
die KlasseListAdapter
verwenden. Wenn SieListAdapter
verwenden, müssen Sie jedoch einen eigenen Adapter für andere Layouts schreiben. In diesem Codelab wird gezeigt, wie das geht. - Wenn Sie das Intention-Menü in Android Studio öffnen möchten, platzieren Sie den Cursor auf einem beliebigen Codeelement und drücken Sie
Alt+Enter
(Option+Enter
auf einem Mac). Dieses Menü ist besonders hilfreich, um Code umzugestalten und Stubs zum Implementieren von Methoden zu erstellen. Das Menü ist kontextbezogen. Sie müssen den Cursor also genau positionieren, um das richtige Menü aufzurufen.
Datenbindung:
- Verwenden Sie die Datenbindung im Elementlayout, um Daten an die Ansichten zu binden.
Bindungsadapter:
- Bisher haben Sie
Transformations
verwendet, um Strings aus Daten zu erstellen. Wenn Sie Daten unterschiedlicher oder komplexer Typen binden müssen, stellen Sie Bindungsadapter bereit, damit die Datenbindung sie verwenden kann. - Um einen Binding-Adapter zu deklarieren, definieren Sie eine Methode, die ein Element und eine Ansicht akzeptiert, und versehen Sie die Methode mit der Annotation
@BindingAdapter
. In Kotlin können Sie den Binding-Adapter als Erweiterungsfunktion fürView
schreiben. Übergeben Sie den Namen der Eigenschaft, die vom Adapter angepasst wird. Beispiel:
@BindingAdapter("sleepDurationFormatted")
- Legen Sie im XML-Layout eine
app
-Property mit demselben Namen wie der Binding-Adapter fest. Übergeben Sie eine Variable mit den Daten. Beispiel:
.app:sleepDurationFormatted="@{sleep}"
Udacity-Kurse:
Android-Entwicklerdokumentation:
- Liste mit RecyclerView erstellen
RecyclerView
DiffUtil
- Data Binding Library
- Bindungsadapter
notifyDataSetChanged()
Transformations
Weitere Ressourcen:
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
Was ist erforderlich, um DiffUtil
zu verwenden? Wähle alle zutreffenden Antworten aus.
▢ Erweitern Sie die Klasse ItemCallBack
.
▢ Überschreiben areItemsTheSame()
.
▢ Überschreiben areContentsTheSame()
.
▢ Mit der Datenbindung können Sie die Unterschiede zwischen Elementen nachverfolgen.
Frage 2
Welche der folgenden Aussagen zu Binding-Adaptern sind richtig?
▢ Ein Binding-Adapter ist eine Funktion, die mit @BindingAdapter
annotiert ist.
▢ Mit einem Binding-Adapter können Sie die Datenformatierung vom View-Holder trennen.
▢ Wenn Sie Binding-Adapter verwenden möchten, müssen Sie RecyclerViewAdapter
verwenden.
▢ Binding-Adapter sind eine gute Lösung, wenn Sie komplexe Daten transformieren müssen.
Frage 3
Wann sollten Sie Transformations
anstelle eines Binding-Adapters verwenden? Wähle alle zutreffenden Antworten aus.
▢ Ihre Daten sind einfach.
▢ Sie formatieren einen String.
▢ Ihre Liste ist sehr lang.
▢ Ihre ViewHolder
enthält nur eine Ansicht.
Nächste Lektion: