Android Kotlin Fundamentals 07.2: DiffUtil i powiązanie danych z RecyclerView

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 z Adapter, ViewHolder i układem elementów.

Czego się nauczysz

  • Jak używać DiffUtil do skutecznego aktualizowania listy wyświetlanej przez RecyclerView.
  • 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, ViewModelLiveData 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.

  1. W razie potrzeby pobierz aplikację RecyclerViewDiffUtilDataBinding-Starter z GitHuba i otwórz projekt w Android Studio.
  2. Uruchom aplikację.
  3. Otwórz plik SleepNightAdapter.kt.
  4. 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 obiekt SleepNight reprezentuje jedną noc snu, jego czas trwania i jakość.
  • Funkcja SleepNightAdapter dostosowuje listę obiektów SleepNight do formatu, który może być używany i wyświetlany przez RecyclerView.
  • Adapter SleepNightAdapter tworzy ViewHolders, które zawierają widoki, dane i metainformacje potrzebne do wyświetlania danych w widoku recyklera.
  • RecyclerView używa SleepNightAdapter, aby określić liczbę elementów do wyświetlenia (getItemCount()). RecyclerView używa onCreateViewHolder()onBindViewHolder(), 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()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.

  1. Otwórz pokój SleepNightAdapter.kt.
  2. Pod pełną definicją klasy SleepNightAdapter utwórz nową klasę najwyższego poziomu o nazwie SleepNightDiffCallback, która rozszerza klasę DiffUtil.ItemCallback. Przekaż SleepNight jako parametr ogólny.
class SleepNightDiffCallback : DiffUtil.ItemCallback<SleepNight>() {
}
  1. Umieść kursor w nazwie zajęć SleepNightDiffCallback.
  2. Naciśnij Alt+Enter (Option+Enter na Macu) i kliknij Implement Members (Wdróż członków).
  3. W wyświetlonym oknie kliknij z przytrzymanym klawiszem Shift, aby wybrać metody areItemsTheSame()areContentsTheSame(), a potem kliknij OK.

    W sekcji SleepNightDiffCallback 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.
    }
  1. W sekcji areItemsTheSame() zastąp TODO kodem, który sprawdza, czy 2 przekazane elementy SleepNight, oldItemnewItem, są takie same. Jeśli produkty mają ten sam atrybut nightId, 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
}
  1. areContentsTheSame() sprawdź, czy oldItemnewItem zawierają te same dane, czyli czy są równe. Sprawdzanie równości obejmie wszystkie pola, ponieważ SleepNight to klasa danych. Klasy Data automatycznie definiują equals i kilka innych metod. Jeśli występują różnice między oldItem a newItem, ten kod informuje DiffUtil, ż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

  1. W pliku SleepNightAdapter.kt zmień sygnaturę klasy SleepNightAdapter, aby rozszerzyć ListAdapter.
  2. Jeśli pojawi się prośba, zaimportuj androidx.recyclerview.widget.ListAdapter.
  3. Dodaj SleepNight jako pierwszy argument do funkcji ListAdapter przed SleepNightAdapter.ViewHolder.
  4. Dodaj SleepNightDiffCallback() jako parametr konstruktora. ListAdapter wykorzysta tę informację, aby określić, co się zmieniło na liście. Gotowy podpis klasy SleepNightAdapter powinien wyglądać jak poniżej.
class SleepNightAdapter : ListAdapter<SleepNight, SleepNightAdapter.ViewHolder>(SleepNightDiffCallback()) {
  1. W klasie SleepNightAdapter usuń pole data, w tym setter. Nie jest już potrzebna, ponieważ ListAdapter śledzi listę za Ciebie.
  2. Usuń zastąpienie getItemCount(), ponieważ ListAdapter implementuje tę metodę za Ciebie.
  3. Aby usunąć błąd w onBindViewHolder(), zmień zmienną item. Zamiast używać data do uzyskiwania item, wywołuj metodę getItem(position) udostępnianą przez ListAdapter.
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.

  1. Otwórz pokój SleepTrackerFragment.kt.
  2. W onCreateView() w obserwatorze na sleepTrackerViewModel znajdź błąd, w którym występuje odwołanie do usuniętej zmiennej data.
  3. Zastąp adapter.data = it połączeniem z numerem adapter.submitList(it). Zaktualizowany kod znajdziesz poniżej.

sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
   it?.let {
       adapter.submitList(it)
   }
})
  1. 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

  1. Otwórz plik układu list_item_sleep_night.xml na karcie Tekst.
  2. Umieść kursor na tagu ConstraintLayout i naciśnij Alt+Enter (Option+Enter na Macu). Otworzy się menu intencji (menu „szybka poprawka”).
  3. 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>.
  4. W razie potrzeby przewiń z powrotem na górę i w tagu <data> zadeklaruj zmienną o nazwie sleep.
  5. 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>
  1. 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ązania ListItemSleepNightBinding wraz z powiązanym kodem zostanie dodany do wygenerowanych plików projektu.

Krok 2. Rozwiń układ elementu za pomocą powiązania danych

  1. Otwórz pokój SleepNightAdapter.kt.
  2. W klasie ViewHolder znajdź metodę from().
  3. Usuń deklarację zmiennej view.

Kod do usunięcia:

val view = layoutInflater
       .inflate(R.layout.list_item_sleep_night, parent, false)
  1. W miejscu zmiennej view zdefiniuj nową zmienną o nazwie binding, która rozszerza obiekt powiązania ListItemSleepNightBinding, jak pokazano poniżej. Zaimportuj niezbędny obiekt powiązania.
val binding =
ListItemSleepNightBinding.inflate(layoutInflater, parent, false)
  1. Na końcu funkcji zamiast zwracać view, zwróć binding.
return ViewHolder(binding)
  1. Aby pozbyć się błędu, umieść kursor na słowie binding. Naciśnij Alt+Enter (Option+Enter na Macu), aby otworzyć menu intencji.
  1. 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.

  1. Przewiń w górę do definicji klasy ViewHolder, aby zobaczyć zmianę w sygnaturze. Wyświetli się błąd dotyczący itemView, ponieważ w metodzie from() zmieniono itemView na binding.

    W definicji klasy ViewHolder kliknij prawym przyciskiem myszy jedno z wystąpień itemView i wybierz Refaktoryzacja > Zmień nazwę. Zmień nazwę na binding.
  2. Dodaj przed parametrem konstruktora binding znak val, aby przekształcić go we właściwość.
  3. W wywołaniu klasy nadrzędnej RecyclerView.ViewHolder zmień parametr z binding na binding.root. Musisz przekazać View, a binding.root to główny element ConstraintLayout w układzie produktu.
  4. 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, qualityqualityImage, aby używać obiektu binding zamiast findViewById().

  1. Zmień inicjalizacje zmiennych sleepLength, qualityStringqualityImage, aby używać widoków obiektu binding, 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.

  1. Kliknij prawym przyciskiem myszy nazwy usług sleepLength, qualityqualityImage. Wybierz Refactor > Inline lub naciśnij Control+Command+N (Option+Command+N na Macu).
  2. Uruchom aplikację. (Jeśli projekt zawiera błędy, może być konieczne wyczyszczenieponowne 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.

  1. Otwórz pokój SleepNightAdapater.kt.
  2. W klasie ViewHolder znajdź metodę bind() i przypomnij sobie, do czego służy. Kod obliczający wartości binding.sleepLength, binding.qualitybinding.qualityImage umieścisz w adapterze. (Na razie pozostaw kod bez zmian. Przeniesiesz go w późniejszym kroku).
  3. W pakiecie sleeptracker utwórz i otwórz plik o nazwie BindingUtils.kt.
  4. Zadeklaruj funkcję rozszerzenia w TextView o nazwie setSleepDurationFormatted i przekaż SleepNight. Ta funkcja będzie adapterem do obliczania i formatowania czasu trwania snu.
fun TextView.setSleepDurationFormatted(item: SleepNight) {}
  1. W treści setSleepDurationFormatted powiąż dane z widokiem tak jak w ViewHolder.bind(). Wywołaj convertDurationToFormatted(), a następnie ustaw text elementu TextView na sformatowany tekst. (Ponieważ jest to funkcja rozszerzenia w TextView, możesz bezpośrednio uzyskać dostęp do właściwości text).
text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, context.resources)
  1. Aby poinformować o tym adapterze wiązania, dodaj do funkcji adnotację @BindingAdapter.
  2. Ta funkcja jest adapterem atrybutu sleepDurationFormatted, więc przekaż sleepDurationFormatted jako argument do @BindingAdapter.
@BindingAdapter("sleepDurationFormatted")
  1. Drugi adapter ustawia jakość snu na podstawie wartości w obiekcie SleepNight. Utwórz funkcję rozszerzenia o nazwie setSleepQualityString()TextView i przekaż SleepNight.
  2. W treści powiąż dane z widokiem tak jak w ViewHolder.bind(). Wywołaj convertNumericQualityToString i ustaw text.
  3. Dodaj do funkcji adnotację @BindingAdapter("sleepQualityString").
@BindingAdapter("sleepQualityString")
fun TextView.setSleepQualityString(item: SleepNight) {
   text = convertNumericQualityToString(item.sleepQuality, context.resources)
}
  1. Trzeci adapter powiązania ustawia obraz w widoku obrazu. Utwórz funkcję rozszerzenia w ImageView, wywołaj setSleepImage i użyj kodu z ViewHolder.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

  1. Otwórz pokój SleepNightAdapter.kt.
  2. 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) {
}
  1. W obiekcie bind() przypisz stan uśpienia do item, ponieważ musisz poinformować obiekt powiązania o nowym obiekcie SleepNight.
binding.sleep = item
  1. 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 w RecyclerView, ponieważ może to nieco przyspieszyć określanie rozmiaru widoków.
 binding.executePendingBindings()

Krok 3. Dodaj powiązania do układu XML

  1. Otwórz pokój list_item_sleep_night.xml.
  2. 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 do sleepImage, adapter dostosuje dane z SleepNight.
app:sleepImage="@{sleep}"
  1. Zrób to samo w przypadku widoków tekstu sleep_lengthquality_string. Gdy odwołujesz się do sleepDurationFormatted lub sleepQualityString, adaptery dostosowują dane z SleepNight.
app:sleepDurationFormatted="@{sleep}"
app:sleepQualityString="@{sleep}"
  1. 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 nazwie DiffUtil, która służy do obliczania różnic między dwiema listami.
  • DiffUtil ma klasę o nazwie ItemCallBack, którą rozszerzasz, aby obliczyć różnicę między dwiema listami.
  • W klasie ItemCallback musisz zastąpić metody areItemsTheSame() i areContentsTheSame().

ListAdapter:

  • Aby bezpłatnie zarządzać listami, możesz użyć klasy ListAdapter zamiast RecyclerView.Adapter. Jeśli jednak używasz ListAdapter, 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 w View. 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:

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ę: 7.3. GridLayout z RecyclerView