Ten moduł Codelab jest częścią kursu Android Kotlin Fundamentals. Najwięcej korzyści przyniesie Ci ukończenie wszystkich ćwiczeń w kolejności. Wszystkie ćwiczenia z tego kursu znajdziesz na stronie docelowej kursu Android Kotlin Fundamentals.
Wprowadzenie
W poprzednich ćwiczeniach z programowania zaktualizowaliśmy aplikację TrackMySleepQuality, aby wyświetlała dane o jakości snu w RecyclerView
. Techniki, których używasz do tworzenia pierwszego RecyclerView
, wystarczą w przypadku większości RecyclerViews
wyświetlających proste listy, które nie są zbyt duże. Istnieje jednak wiele technik, które sprawiają, że RecyclerView
jest bardziej wydajny w przypadku dużych list, a kod jest łatwiejszy w utrzymaniu i rozbudowie w przypadku złożonych list i siatek.
W tym ćwiczeniu z programowania rozbudujesz aplikację do śledzenia snu z poprzedniego ćwiczenia. Dowiesz się, jak skuteczniej aktualizować listę danych o śnie, i jak używać powiązania danych z RecyclerView
. (Jeśli nie masz aplikacji z poprzednich zajęć, możesz pobrać kod początkowy do tych zajęć).
Co warto wiedzieć
- Tworzenie podstawowego interfejsu użytkownika za pomocą aktywności, fragmentów i widoków.
- przechodzenie między fragmentami i używanie
safeArgs
do przekazywania danych między fragmentami; - Wyświetlanie modeli, fabryk modeli, przekształceń i
LiveData
oraz ich obserwatorów. - Jak utworzyć bazę danych
Room
, utworzyć DAO i zdefiniować encje. - Jak używać korutyn do obsługi baz danych i innych długotrwałych zadań.
- Jak wdrożyć podstawowy
RecyclerView
zAdapter
,ViewHolder
i układem elementów.
Czego się nauczysz
- Jak używać
DiffUtil
do skutecznego aktualizowania listy wyświetlanej przezRecyclerView
. - Jak używać wiązania danych w przypadku
RecyclerView
. - Jak używać adapterów powiązań do przekształcania danych.
Jakie zadania wykonasz
- Skorzystaj z aplikacji TrackMySleepQuality z poprzedniego samouczka z tej serii.
- Zaktualizuj
SleepNightAdapter
, aby skutecznie aktualizować listę za pomocąDiffUtil
. - Zaimplementuj powiązanie danych dla elementu
RecyclerView
, używając adapterów powiązań do przekształcania danych.
Aplikacja do śledzenia snu ma 2 ekrany reprezentowane przez fragmenty, jak pokazano na ilustracji poniżej.
Pierwszy ekran, widoczny po lewej stronie, zawiera przyciski rozpoczynania i zatrzymywania śledzenia. Na ekranie wyświetlają się niektóre dane dotyczące snu użytkownika. Przycisk Wyczyść trwale usuwa wszystkie dane zebrane przez aplikację na temat użytkownika. Drugi ekran, widoczny po prawej stronie, służy do wybierania oceny jakości snu.
Ta aplikacja jest zaprojektowana tak, aby używać kontrolera interfejsu, ViewModel
i LiveData
oraz bazy danych Room
do przechowywania danych o śnie.
Dane o śnie są wyświetlane w RecyclerView
. W tym ćwiczeniu utworzysz część DiffUtil
i powiązanie danych dla RecyclerView
. Po ukończeniu tego laboratorium kodowania Twoja aplikacja będzie wyglądać dokładnie tak samo, ale będzie wydajniejsza, łatwiejsza do skalowania i utrzymania.
Możesz nadal używać aplikacji SleepTracker z poprzedniego laboratorium programowania lub pobrać aplikację RecyclerViewDiffUtilDataBinding-Starter z GitHub.
- W razie potrzeby pobierz aplikację RecyclerViewDiffUtilDataBinding-Starter z GitHuba i otwórz projekt w Android Studio.
- Uruchom aplikację.
- Otwórz plik
SleepNightAdapter.kt
. - Sprawdź kod, aby zapoznać się ze strukturą aplikacji. Na poniższym diagramie znajdziesz podsumowanie używania
RecyclerView
ze wzorcem adaptera do wyświetlania użytkownikowi danych o śnie.
- Na podstawie danych wejściowych użytkownika aplikacja tworzy listę
SleepNight
obiektów. Każdy obiektSleepNight
reprezentuje jedną noc snu, jego czas trwania i jakość. - Funkcja
SleepNightAdapter
dostosowuje listę obiektówSleepNight
do formatu, który może być używany i wyświetlany przezRecyclerView
. - Adapter
SleepNightAdapter
tworzyViewHolders
, które zawierają widoki, dane i metainformacje potrzebne do wyświetlania danych w widoku recyklera. RecyclerView
używaSleepNightAdapter
, aby określić liczbę elementów do wyświetlenia (getItemCount()
).RecyclerView
używaonCreateViewHolder()
ionBindViewHolder()
, aby uzyskać uchwyty widoku powiązane z danymi do wyświetlenia.
Metoda notifyDataSetChanged() jest nieefektywna
Aby poinformować RecyclerView
, że element na liście uległ zmianie i wymaga aktualizacji, bieżący kod wywołuje notifyDataSetChanged()
w SleepNightAdapter
, jak pokazano poniżej.
var data = listOf<SleepNight>()
set(value) {
field = value
notifyDataSetChanged()
}
Jednak notifyDataSetChanged()
informuje RecyclerView
, że cała lista może być nieprawidłowa. W rezultacie RecyclerView
ponownie wiąże i rysuje każdy element na liście, w tym elementy, które nie są widoczne na ekranie. To dużo niepotrzebnej pracy. W przypadku dużych lub złożonych list ten proces może trwać na tyle długo, że wyświetlacz będzie migać lub zacinać się podczas przewijania listy przez użytkownika.
Aby rozwiązać ten problem, możesz dokładnie określić, co się zmieniło w RecyclerView
. RecyclerView
może wtedy aktualizować tylko widoki, które uległy zmianie na ekranie.
RecyclerView
ma rozbudowany interfejs API do aktualizowania pojedynczego elementu. Możesz użyć notifyItemChanged()
, aby poinformować RecyclerView
o zmianie elementu. Podobnych funkcji możesz używać w przypadku elementów, które zostały dodane, usunięte lub przeniesione. Możesz to zrobić ręcznie, ale to zadanie nie będzie proste i może wymagać sporo kodu.
Na szczęście istnieje lepszy sposób.
DiffUtil jest wydajny i wykonuje za Ciebie całą ciężką pracę.
RecyclerView
ma klasę o nazwie DiffUtil
, która służy do obliczania różnic między dwiema listami. DiffUtil
porównuje starą i nową listę i wykrywa różnice. Wyszukuje elementy, które zostały dodane, usunięte lub zmienione. Następnie używa algorytmu o nazwie Eugene W. algorytmu różnicowego Myersa, aby określić minimalną liczbę zmian, które należy wprowadzić na starej liście, aby uzyskać nową listę.
Gdy DiffUtil
wykryje zmiany, RecyclerView
może użyć tych informacji, aby zaktualizować tylko zmienione, dodane, usunięte lub przeniesione elementy, co jest znacznie wydajniejsze niż ponowne tworzenie całej listy.
W tym zadaniu uaktualnisz SleepNightAdapter
, aby używać DiffUtil
do optymalizacji RecyclerView
pod kątem zmian w danych.
Krok 1. Wdróż SleepNightDiffCallback
Aby korzystać z funkcji klasy DiffUtil
, rozszerz DiffUtil.ItemCallback
.
- Otwórz pokój
SleepNightAdapter.kt
. - Pod pełną definicją klasy
SleepNightAdapter
utwórz nową klasę najwyższego poziomu o nazwieSleepNightDiffCallback
, która rozszerza klasęDiffUtil.ItemCallback
. PrzekażSleepNight
jako parametr ogólny.
class SleepNightDiffCallback : DiffUtil.ItemCallback<SleepNight>() {
}
- Umieść kursor w nazwie zajęć
SleepNightDiffCallback
. - Naciśnij
Alt+Enter
(Option+Enter
na Macu) i kliknij Implement Members (Wdróż członków). - W wyświetlonym oknie kliknij z przytrzymanym klawiszem Shift, aby wybrać metody
areItemsTheSame()
iareContentsTheSame()
, a potem kliknij OK.
W sekcjiSleepNightDiffCallback
zostaną wygenerowane szablony tych 2 metod, jak pokazano poniżej.DiffUtil
korzysta z tych 2 metod, aby określić, jak zmieniła się lista i jej elementy.
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.
}
- W sekcji
areItemsTheSame()
zastąpTODO
kodem, który sprawdza, czy 2 przekazane elementySleepNight
,oldItem
inewItem
, są takie same. Jeśli produkty mają ten sam atrybutnightId
, są tym samym produktem, więc zwróć wartośćtrue
. W przeciwnym razie zwróć wartośćfalse
.DiffUtil
używa tego testu, aby sprawdzić, czy element został dodany, usunięty lub przeniesiony.
override fun areItemsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
return oldItem.nightId == newItem.nightId
}
- W
areContentsTheSame()
sprawdź, czyoldItem
inewItem
zawierają te same dane, czyli czy są równe. Sprawdzanie równości obejmie wszystkie pola, ponieważSleepNight
to klasa danych. KlasyData
automatycznie definiująequals
i kilka innych metod. Jeśli występują różnice międzyoldItem
anewItem
, ten kod informujeDiffUtil
, że element został zaktualizowany.
override fun areContentsTheSame(oldItem: SleepNight, newItem: SleepNight): Boolean {
return oldItem == newItem
}
Wyświetlanie zmieniającej się listy za pomocą elementu RecyclerView
to powszechny wzorzec. RecyclerView
udostępnia klasę adaptera ListAdapter
, która pomaga tworzyć adapter RecyclerView
oparty na liście.
ListAdapter
śledzi listę i powiadamia adapter o jej aktualizacji.
Krok 1. Zmień adapter, aby rozszerzyć ListAdapter
- W pliku
SleepNightAdapter.kt
zmień sygnaturę klasySleepNightAdapter
, aby rozszerzyćListAdapter
. - Jeśli pojawi się prośba, zaimportuj
androidx.recyclerview.widget.ListAdapter
. - Dodaj
SleepNight
jako pierwszy argument do funkcjiListAdapter
przedSleepNightAdapter.ViewHolder
. - Dodaj
SleepNightDiffCallback()
jako parametr konstruktora.ListAdapter
wykorzysta tę informację, aby określić, co się zmieniło na liście. Gotowy podpis klasySleepNightAdapter
powinien wyglądać jak poniżej.
class SleepNightAdapter : ListAdapter<SleepNight, SleepNightAdapter.ViewHolder>(SleepNightDiffCallback()) {
- W klasie
SleepNightAdapter
usuń poledata
, w tym setter. Nie jest już potrzebna, ponieważListAdapter
śledzi listę za Ciebie. - Usuń zastąpienie
getItemCount()
, ponieważListAdapter
implementuje tę metodę za Ciebie. - Aby usunąć błąd w
onBindViewHolder()
, zmień zmiennąitem
. Zamiast używaćdata
do uzyskiwaniaitem
, wywołuj metodęgetItem(position)
udostępnianą przezListAdapter
.
val item = getItem(position)
Krok 2. Użyj funkcji submitList(), aby aktualizować listę
Kod musi informować ListAdapter
o dostępności zmienionej listy. ListAdapter
udostępnia metodę o nazwie submitList()
, która informuje ListAdapter
o dostępności nowej wersji listy. Gdy ta metoda jest wywoływana, ListAdapter
porównuje nową listę ze starą i wykrywa elementy, które zostały dodane, usunięte, przeniesione lub zmienione. Następnie ListAdapter
aktualizuje wyświetlane przez RecyclerView
produkty.
- Otwórz pokój
SleepTrackerFragment.kt
. - W
onCreateView()
w obserwatorze nasleepTrackerViewModel
znajdź błąd, w którym występuje odwołanie do usuniętej zmiennejdata
. - Zastąp
adapter.data = it
połączeniem z numeremadapter.submitList(it)
. Zaktualizowany kod znajdziesz poniżej.
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
it?.let {
adapter.submitList(it)
}
})
- Uruchom aplikację. Będzie działać szybciej, choć może to być niezauważalne, jeśli lista jest krótka.
W tym zadaniu użyjesz tej samej techniki co w poprzednich modułach, aby skonfigurować powiązanie danych, i wyeliminujesz wywołania funkcji findViewById()
.
Krok 1. Dodaj powiązanie danych do pliku układu
- Otwórz plik układu
list_item_sleep_night.xml
na karcie Tekst. - Umieść kursor na tagu
ConstraintLayout
i naciśnijAlt+Enter
(Option+Enter
na Macu). Otworzy się menu intencji (menu „szybka poprawka”). - Wybierz Convert to data binding layout (Przekonwertuj na układ powiązania danych). Spowoduje to umieszczenie układu w tagu
<layout>
i dodanie w nim tagu<data>
. - W razie potrzeby przewiń z powrotem na górę i w tagu
<data>
zadeklaruj zmienną o nazwiesleep
. - Ustaw
type
jako pełną nazwęSleepNight
,com.example.android.trackmysleepquality.database.SleepNight
. Gotowy tag<data>
powinien wyglądać jak poniżej.
<data>
<variable
name="sleep"
type="com.example.android.trackmysleepquality.database.SleepNight"/>
</data>
- Aby wymusić utworzenie obiektu
Binding
, wybierz Build > Clean Project (Skompiluj > Wyczyść projekt), a potem Build > Rebuild Project (Skompiluj > Skompiluj projekt ponownie). (Jeśli problem nadal występuje, wybierz File > Invalidate Caches / Restart). Obiekt wiązaniaListItemSleepNightBinding
wraz z powiązanym kodem zostanie dodany do wygenerowanych plików projektu.
Krok 2. Rozwiń układ elementu za pomocą powiązania danych
- Otwórz pokój
SleepNightAdapter.kt
. - W klasie
ViewHolder
znajdź metodęfrom()
. - Usuń deklarację zmiennej
view
.
Kod do usunięcia:
val view = layoutInflater
.inflate(R.layout.list_item_sleep_night, parent, false)
- W miejscu zmiennej
view
zdefiniuj nową zmienną o nazwiebinding
, która rozszerza obiekt powiązaniaListItemSleepNightBinding
, jak pokazano poniżej. Zaimportuj niezbędny obiekt powiązania.
val binding =
ListItemSleepNightBinding.inflate(layoutInflater, parent, false)
- Na końcu funkcji zamiast zwracać
view
, zwróćbinding
.
return ViewHolder(binding)
- Aby pozbyć się błędu, umieść kursor na słowie
binding
. NaciśnijAlt+Enter
(Option+Enter
na Macu), aby otworzyć menu intencji.
- Wybierz Change parameter 'itemView' type of primary constructor of class 'ViewHolder' to 'ListItemSleepNightBinding' (Zmień typ parametru „itemView” głównego konstruktora klasy „ViewHolder” na „ListItemSleepNightBinding”). Spowoduje to zaktualizowanie typu parametru klasy
ViewHolder
.
- Przewiń w górę do definicji klasy
ViewHolder
, aby zobaczyć zmianę w sygnaturze. Wyświetli się błąd dotyczącyitemView
, ponieważ w metodziefrom()
zmienionoitemView
nabinding
.
W definicji klasyViewHolder
kliknij prawym przyciskiem myszy jedno z wystąpieńitemView
i wybierz Refaktoryzacja > Zmień nazwę. Zmień nazwę nabinding
. - Dodaj przed parametrem konstruktora
binding
znakval
, aby przekształcić go we właściwość. - W wywołaniu klasy nadrzędnej
RecyclerView.ViewHolder
zmień parametr zbinding
nabinding.root
. Musisz przekazaćView
, abinding.root
to główny elementConstraintLayout
w układzie produktu. - Gotowa deklaracja klasy powinna wyglądać tak, jak pokazano poniżej.
class ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root){
Widzisz też błąd dotyczący wywołań funkcji findViewById()
, który musisz naprawić.
Krok 3. Zastąp findViewById()
Możesz teraz zaktualizować właściwości sleepLength
, quality
i qualityImage
, aby używać obiektu binding
zamiast findViewById()
.
- Zmień inicjalizacje zmiennych
sleepLength
,qualityString
iqualityImage
, aby używać widoków obiektubinding
, jak pokazano poniżej. Po tym kod nie powinien już zawierać żadnych błędów.
val sleepLength: TextView = binding.sleepLength
val quality: TextView = binding.qualityString
val qualityImage: ImageView = binding.qualityImage
Gdy obiekt wiązania jest już na miejscu, nie musisz już w ogóle definiować właściwości sleepLength
, quality
ani qualityImage
. DataBinding
będzie buforować wyszukiwania, więc nie musisz deklarować tych właściwości.
- Kliknij prawym przyciskiem myszy nazwy usług
sleepLength
,quality
iqualityImage
. Wybierz Refactor > Inline lub naciśnijControl+Command+N
(Option+Command+N
na Macu). - Uruchom aplikację. (Jeśli projekt zawiera błędy, może być konieczne wyczyszczenie i ponowne skompilowanie projektu).
W tym zadaniu zaktualizujesz aplikację, aby używała powiązania danych z adapterami powiązań do ustawiania danych w widokach.
W poprzednich ćwiczeniach z programowania używaliśmy klasy Transformations
do pobierania LiveData
i generowania sformatowanych ciągów znaków do wyświetlania w widokach tekstowych. Jeśli jednak musisz powiązać różne typy lub typy złożone, możesz podać adaptery powiązań, aby ułatwić powiązanie danych z tymi typami. Adaptery powiązań to adaptery, które pobierają dane i przekształcają je w coś, co może być użyte przez powiązanie danych do powiązania widoku, np. tekstu lub obrazu.
Zaimplementujesz 3 adaptery powiązań: jeden dla obrazu wysokiej jakości i po jednym dla każdego pola tekstowego. Podsumowując, aby zadeklarować adapter powiązania, zdefiniuj metodę, która przyjmuje element i widok, i dodaj do niej adnotację @BindingAdapter
. W treści metody implementujesz przekształcenie. W Kotlinie możesz napisać adapter powiązania jako funkcję rozszerzenia w klasie widoku, która otrzymuje dane.
Krok 1. Utwórz adaptery powiązań
Pamiętaj, że w tym kroku musisz zaimportować kilka zajęć, które nie będą wymienione osobno.
- Otwórz pokój
SleepNightAdapater.kt
. - W klasie
ViewHolder
znajdź metodębind()
i przypomnij sobie, do czego służy. Kod obliczający wartościbinding.sleepLength
,binding.quality
ibinding.qualityImage
umieścisz w adapterze. (Na razie pozostaw kod bez zmian. Przeniesiesz go w późniejszym kroku). - W pakiecie
sleeptracker
utwórz i otwórz plik o nazwieBindingUtils.kt
. - Zadeklaruj funkcję rozszerzenia w
TextView
o nazwiesetSleepDurationFormatted
i przekażSleepNight
. Ta funkcja będzie adapterem do obliczania i formatowania czasu trwania snu.
fun TextView.setSleepDurationFormatted(item: SleepNight) {}
- W treści
setSleepDurationFormatted
powiąż dane z widokiem tak jak wViewHolder.bind()
. WywołajconvertDurationToFormatted()
, a następnie ustawtext
elementuTextView
na sformatowany tekst. (Ponieważ jest to funkcja rozszerzenia wTextView
, możesz bezpośrednio uzyskać dostęp do właściwościtext
).
text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, context.resources)
- Aby poinformować o tym adapterze wiązania, dodaj do funkcji adnotację
@BindingAdapter
. - Ta funkcja jest adapterem atrybutu
sleepDurationFormatted
, więc przekażsleepDurationFormatted
jako argument do@BindingAdapter
.
@BindingAdapter("sleepDurationFormatted")
- Drugi adapter ustawia jakość snu na podstawie wartości w obiekcie
SleepNight
. Utwórz funkcję rozszerzenia o nazwiesetSleepQualityString()
wTextView
i przekażSleepNight
. - W treści powiąż dane z widokiem tak jak w
ViewHolder.bind()
. WywołajconvertNumericQualityToString
i ustawtext
. - Dodaj do funkcji adnotację
@BindingAdapter("sleepQualityString")
.
@BindingAdapter("sleepQualityString")
fun TextView.setSleepQualityString(item: SleepNight) {
text = convertNumericQualityToString(item.sleepQuality, context.resources)
}
- Trzeci adapter powiązania ustawia obraz w widoku obrazu. Utwórz funkcję rozszerzenia w
ImageView
, wywołajsetSleepImage
i użyj kodu zViewHolder.bind()
, jak pokazano poniżej.
@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
})
}
Krok 2. Zaktualizuj SleepNightAdapter
- Otwórz pokój
SleepNightAdapter.kt
. - Usuń wszystko w metodzie
bind()
, ponieważ możesz teraz używać powiązania danych i nowych adapterów, aby wykonać tę pracę za Ciebie.
fun bind(item: SleepNight) {
}
- W obiekcie
bind()
przypisz stan uśpienia doitem
, ponieważ musisz poinformować obiekt powiązania o nowym obiekcieSleepNight
.
binding.sleep = item
- Pod tym wierszem dodaj
binding.executePendingBindings()
. To wywołanie jest optymalizacją, która powoduje natychmiastowe wykonanie wszystkich oczekujących wiązań danych. Zawsze warto wywoływać metodęexecutePendingBindings()
, gdy używasz adapterów wiążących wRecyclerView
, ponieważ może to nieco przyspieszyć określanie rozmiaru widoków.
binding.executePendingBindings()
Krok 3. Dodaj powiązania do układu XML
- Otwórz pokój
list_item_sleep_night.xml
. - W
ImageView
dodaj właściwośćapp
o takiej samej nazwie jak adapter powiązania, który ustawia obraz. Przekaż zmiennąsleep
, jak pokazano poniżej.
Ta właściwość tworzy połączenie między widokiem a obiektem wiązania za pomocą adaptera. Gdy pojawi się odwołanie dosleepImage
, adapter dostosuje dane zSleepNight
.
app:sleepImage="@{sleep}"
- Zrób to samo w przypadku widoków tekstu
sleep_length
iquality_string
. Gdy odwołujesz się dosleepDurationFormatted
lubsleepQualityString
, adaptery dostosowują dane zSleepNight
.
app:sleepDurationFormatted="@{sleep}"
app:sleepQualityString="@{sleep}"
- Uruchom aplikację. Działa ona dokładnie tak samo jak wcześniej. Adaptery powiązań wykonują całą pracę związaną z formatowaniem i aktualizowaniem widoków w miarę zmian danych, co upraszcza
ViewHolder
i poprawia strukturę kodu.
W przypadku kilku ostatnich ćwiczeń wyświetliłeś(-aś) tę samą listę. Zostało to zaprojektowane tak, aby pokazać, że interfejs Adapter
umożliwia tworzenie kodu na wiele różnych sposobów. Im bardziej złożony jest kod, tym ważniejsze jest jego prawidłowe zaprojektowanie. W aplikacjach produkcyjnych te i inne wzorce są używane w środowisku RecyclerView
. Wszystkie te wzorce działają i każdy z nich ma swoje zalety. Wybór zależy od tego, co tworzysz.
Gratulacje! Jesteś na dobrej drodze do opanowania RecyclerView
na Androidzie.
Projekt Android Studio: RecyclerViewDiffUtilDataBinding.
DiffUtil
:
RecyclerView
ma klasę o nazwieDiffUtil
, która służy do obliczania różnic między dwiema listami.DiffUtil
ma klasę o nazwieItemCallBack
, którą rozszerzasz, aby obliczyć różnicę między dwiema listami.- W klasie
ItemCallback
musisz zastąpić metodyareItemsTheSame()
iareContentsTheSame()
.
ListAdapter
:
- Aby bezpłatnie zarządzać listami, możesz użyć klasy
ListAdapter
zamiastRecyclerView.Adapter
. Jeśli jednak używaszListAdapter
, musisz napisać własny adapter dla innych układów, dlatego w tym laboratorium kodu pokazujemy, jak to zrobić. - Aby otworzyć menu intencji w Android Studio, umieść kursor na dowolnym elemencie kodu i naciśnij
Alt+Enter
(Option+Enter
na Macu). To menu jest szczególnie przydatne do refaktoryzacji kodu i tworzenia stubów do implementacji metod. Menu jest kontekstowe, więc aby uzyskać odpowiednie menu, musisz umieścić kursor w odpowiednim miejscu.
Wiązanie danych:
- Użyj powiązania danych w układzie elementu, aby powiązać dane z widokami.
Adaptery do wiązania:
- Wcześniej używasz funkcji
Transformations
do tworzenia ciągów znaków na podstawie danych. Jeśli musisz powiązać dane różnych lub złożonych typów, udostępnij adaptery powiązań, aby ułatwić powiązanie danych. - Aby zadeklarować adapter powiązania, zdefiniuj metodę, która przyjmuje element i widok, i dodaj do niej adnotację
@BindingAdapter
. W Kotlinie możesz napisać adapter powiązania jako funkcję rozszerzenia wView
. Przekaż nazwę usługi, do której dostosowuje się adapter. Na przykład:
@BindingAdapter("sleepDurationFormatted")
- W układzie XML ustaw właściwość
app
o takiej samej nazwie jak adapter powiązania. Przekaż zmienną z danymi. Na przykład:
.app:sleepDurationFormatted="@{sleep}"
Kursy Udacity:
Dokumentacja dla deweloperów aplikacji na Androida:
- Tworzenie listy za pomocą elementu RecyclerView
RecyclerView
DiffUtil
- Biblioteka powiązań danych
- Adaptery wiązań
notifyDataSetChanged()
Transformations
Inne zasoby:
W tej sekcji znajdziesz listę możliwych zadań domowych dla uczniów, którzy wykonują ten moduł w ramach kursu prowadzonego przez instruktora. Nauczyciel musi:
- W razie potrzeby przypisz pracę domową.
- Poinformuj uczniów, jak przesyłać projekty.
- Oceń zadania domowe.
Instruktorzy mogą korzystać z tych sugestii w dowolnym zakresie i mogą zadawać inne zadania domowe, które uznają za odpowiednie.
Jeśli wykonujesz ten kurs samodzielnie, możesz użyć tych zadań domowych, aby sprawdzić swoją wiedzę.
Odpowiedz na te pytania
Pytanie 1
Które z tych elementów są niezbędne do korzystania z DiffUtil
? Zaznacz wszystkie pasujące opcje.
▢ Wydłuż zajęcia ItemCallBack
.
▢ Zastąp areItemsTheSame()
.
▢ Zastąp areContentsTheSame()
.
▢ Używaj wiązania danych, aby śledzić różnice między elementami.
Pytanie 2
Które z tych stwierdzeń dotyczących adapterów powiązań są prawdziwe?
▢ Adapter powiązania to funkcja oznaczona adnotacją @BindingAdapter
.
▢ Użycie adaptera powiązań umożliwia oddzielenie formatowania danych od obiektu widoku.
▢ Jeśli chcesz używać adapterów wiążących, musisz użyć RecyclerViewAdapter
.
▢ Adaptery powiązań to dobre rozwiązanie, gdy musisz przekształcić złożone dane.
Pytanie 3
Kiedy warto użyć Transformations
zamiast adaptera powiązania? Zaznacz wszystkie pasujące opcje.
▢ Dane są proste.
▢ Formatujesz ciąg znaków.
▢ Twoja lista jest bardzo długa.
▢ Twój ViewHolder
zawiera tylko jeden widok.
Rozpocznij kolejną lekcję: