Te ćwiczenia są częścią kursu Android Kotlin Fundamentals. Skorzystaj z tego kursu, jeśli będziesz wykonywać kolejno kilka ćwiczeń z programowania. Wszystkie ćwiczenia z kursu są wymienione na stronie docelowej ćwiczeń z programowania na temat Kotlin.
Wprowadzenie
W poprzednich ćwiczeniach z programowania na ten kurs wykorzystywana była funkcja findViewById()
do sprawdzania odwołań do widoków. Gdy aplikacja ma złożone hierarchie widoków danych, findViewById()
jest kosztowna i spowalnia ją, ponieważ Android przechodzi przez hierarchię widoków, zaczynając od poziomu głównego, aż znajdzie odpowiedni widok. Na szczęście jest lepszy sposób.
Do ustawiania danych w widokach służą zasoby ciągu znaków i dane z aktywności. Lepszy byłby widok danych, gdyby wiedział o nich dane. Na szczęście jest to możliwe.
Z tego ćwiczenia dowiesz się, jak używać wiązania danych, aby wyeliminować potrzebę stosowania funkcji findViewById()
. Dowiedz się też, jak korzystać z powiązań danych, by uzyskać dostęp do danych bezpośrednio z poziomu widoku danych.
Co musisz wiedzieć
Pamiętaj:
- Czym jest aktywność i jak ją skonfigurować w narzędziu
onCreate()
. - Tworzenie widoku tekstowego i ustawianie tekstu, który się w nim wyświetla.
- Używanie operatora
findViewById()
do generowania odwołań do widoku. - Tworzenie i edytowanie podstawowego układu XML dla widoku.
Czego się nauczysz
- Jak używać biblioteki wiązania danych, aby wyeliminować nieskuteczne wywołania usługi
findViewById()
. - Jak uzyskać dostęp do danych aplikacji bezpośrednio z pliku XML.
Jakie zadania wykonasz:
- Zmodyfikuj aplikację, aby używała wiązania danych zamiast pliku
findViewById()
, i uzyskiwała dostęp do danych bezpośrednio z plików XML układu.
W tym ćwiczeniu zaczniesz od aplikacji O mnie, by zmienić jej działanie na wiązanie danych. Gdy skończysz, aplikacja będzie wyglądać dokładnie tak samo.
Oto informacje o aplikacji OMem:
- Gdy użytkownik otworzy aplikację, wyświetli się nazwa, pole do wpisania pseudonimu, przycisk Gotowe, obraz gwiazdki i element, który można przewijać.
- Użytkownik może wpisać pseudonim i kliknąć przycisk Gotowe. Pole i przycisk, które można edytować, zostaną zastąpione widokiem tekstowym zawierającym wpisany pseudonim.
Możesz użyć kodu utworzonego w poprzednim kursie lub pobrać kod AboutMeDataBinding-Starter z GitHuba.
Kod podany w poprzednich ćwiczeniach z programowania korzysta z funkcji findViewById()
do uzyskiwania odniesień do widoków.
Za każdym razem, gdy użyjesz widoku findViewById()
, aby wyszukać widok, który został utworzony lub utworzony ponownie, Android w czasie rzeczywistym przegląda hierarchię widoku, aby ją znaleźć. Jeśli Twoja aplikacja ma tylko kilka wyświetleń, nie stanowi to problemu. Jednak aplikacje w wersji produkcyjnej mogą mieć dziesiątki wyświetleń w układzie i nawet w przypadku najlepszego projektu będą zagnieżdżone widoki.
Pomyśl o układzie liniowym zawierającym widok przewijania zawierający widok tekstowy. W przypadku dużej lub szczegółowej hierarchii widoków znalezienie widoku może potrwać wystarczająco długo, aby spowolnić działanie aplikacji u użytkownika. Buforowanie widoków w zmiennych może pomóc, ale nadal musisz zainicjować zmienną dla każdego widoku w każdej przestrzeni nazw. To przekłada się też na liczbę wyświetleń i wiele aktywności.
Jednym z rozwiązań jest utworzenie obiektu zawierającego odwołanie do każdego widoku. Ten obiekt, nazywany obiektem Binding
, może być używany przez całą aplikację. Ta technika nazywa się powiązaniem danych. Po utworzeniu obiektu wiązania na potrzeby aplikacji możesz uzyskać dostęp do widoków i innych danych za pomocą obiektu wiązania, bez konieczności poruszania się po hierarchii widoku i wyszukiwania danych.
Powiązanie danych ma te zalety:
- Kod jest krótszy, łatwiejszy do odczytania i łatwiejszy w utrzymaniu niż kod korzystający z tagu
findByView()
. - Dane i widoki danych są wyraźnie oddzielone. Korzyści wynikające z powiązania danych stają się coraz ważniejsze w dalszej części tego kursu.
- System Android przegląda wyniki tylko raz, aby pobrać każdy widok. Dzieje się tak podczas uruchamiania aplikacji, a nie w czasie, gdy użytkownik wchodzi w interakcję z aplikacją.
- Otrzymujesz bezpieczeństwo typu podczas uzyskiwania dostępu do widoków. (Bezpieczeństwo typu oznacza, że kompilator weryfikuje typy podczas kompilowania, a jeśli spróbujesz przypisać do niego nieprawidłowy typ, wyświetli się błąd).
W tym zadaniu konfigurujesz wiązanie danych i używasz wiązania danych, aby zastąpić wywołania findViewById()
przez wywołania obiektu powiązania.
Krok 1. Włącz wiązanie danych
Aby użyć wiązania danych, musisz włączyć wiązanie danych w pliku Gradle, ponieważ nie jest ono włączone domyślnie. Dzieje się tak, ponieważ wiązanie danych wydłuża czas kompilacji i może wpływać na czas uruchamiania aplikacji.
- Jeśli nie masz aplikacji aboutMe z poprzedniego ćwiczenia z programowania, pobierz z GitHuba kod AboutMeDataBinding-Starter. Otwórz ją w Android Studio.
- Otwórz plik
build.gradle (Module: app)
. - W sekcji
android
przed nawiasem zamykającym dodaj sekcjędataBinding
i ustawenabled
natrue
.
dataBinding {
enabled = true
}
- Gdy pojawi się taka prośba, zsynchronizuj projekt. Jeśli nie pojawi się prośba, wybierz File > Sync Project with Gradle Files.
- Możesz uruchomić aplikację, ale nie zobaczysz żadnych zmian.
Krok 2. Zmień plik układu tak, aby można było go użyć z wiązaniem danych
Aby tworzyć powiązania danych, musisz pakować układ XML tagiem <layout>
. Dzięki temu klasa główna nie jest już grupą widoku danych, a zamiast nich zawiera układ i widoki danych. Będzie on wówczas wiedział o układzie i widokach, które się w nim znajdują.
- Otwórz plik
activity_main.xml
. - Otwórz kartę Tekst.
- Dodaj tag
<layout></layout>
jako najbardziej zewnętrzny tag wokół obiektu<LinearLayout>
.
<layout>
<LinearLayout ... >
...
</LinearLayout>
</layout>
- Wybierz Kod > Zmień format kodu, aby naprawić wcięcie kodu.
Deklaracje przestrzeni nazw muszą znajdować się w tagu zewnętrznym.
- Wytnij deklaracje przestrzeni nazw z
<LinearLayout>
i wklej je w tagu<layout>
. Tag otwierający<layout>
powinien wyglądać tak jak poniżej, a tag<LinearLayout>
powinien zawierać tylko właściwości widoku.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
- Przygotuj i uruchom aplikację, aby sprawdzić, czy wszystko zostało poprawnie ustawione.
Krok 3. Utwórz obiekt wiązania w głównej aktywności
Dodaj odniesienie do obiektu powiązania do głównej aktywności, aby móc go używać do uzyskania dostępu do widoków:
- Otwórz plik
MainActivity.kt
. - Przed
onCreate()
utwórz na najwyższym poziomie zmienną dla obiektu wiązania. Ta zmienna nosi zwykle nazwębinding
.
Typbinding
, klasaActivityMainBinding
, jest tworzony przez kompilator specjalnie dla tej głównej aktywności. Nazwa pochodzi od nazwy pliku układu, czyli „activity_main + Binding
”.
private lateinit var binding: ActivityMainBinding
- Jeśli pojawi się prośba w Android Studio, zaimportuj
ActivityMainBinding
. Jeśli nie pojawi się taka prośba, kliknijActivityMainBinding
i naciśnijAlt+Enter
(Option+Enter
na Macu), by zaimportować tę brakujące zajęcia. (więcej informacji o skrótach klawiszowych znajdziesz w sekcji Skróty klawiszowe).
Instrukcjaimport
powinna wyglądać podobnie do przedstawionej poniżej.
import com.example.android.aboutme.databinding.ActivityMainBinding
Następnie zastąp obecną funkcję setContentView()
instrukcją, która wykonuje tę czynność:
- Utworzy obiekt powiązania.
- Używa funkcji
setContentView()
z klasyDataBindingUtil
do powiązania układuactivity_main
zMainActivity
. Ta funkcjasetContentView()
obsługuje też niektóre konfiguracje wiązania danych dla widoków.
- W
onCreate()
zastąp wywołaniesetContentView()
tym wierszem kodu.
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
- Importuj:
DataBindingUtil
.
import androidx.databinding.DataBindingUtil
Krok 4. Zastąp wszystkie wywołania funkcji „ViewByById()” za pomocą obiektu wiązania
Możesz teraz zastąpić wszystkie wywołania findViewById()
przez odwołania do widoków znajdujących się w obiekcie wiązania. Podczas tworzenia obiektu wiązania kompilator generuje nazwy widoków w obiekcie wiązania na podstawie identyfikatorów widoków w układzie, przekształcając je w wielkość liter wielbłąda. Przykład: done_button
ma postać doneButton
w wiążącym obiekcie, nickname_edit
zmienia się w nicknameEdit
, a nickname_text
– nicknameText
.
- W sekcji
onCreate()
zastąp kod korzystający z tagufindViewById()
, aby znaleźć elementdone_button
kodem, który odwołuje się do przycisku w obiekcie wiązania.
Zastąp ten kod:findViewById<Button>(R.id.
done_button
)
kodem:binding.doneButton
Ukończony kod ustawiający detektor kliknięć wonCreate()
powinien wyglądać tak.
binding.doneButton.setOnClickListener {
addNickname(it)
}
- Zrób to samo w przypadku wszystkich wywołań funkcji
findViewById()
w funkcjiaddNickname()
.
Zastąp wszystkie wystąpienia elementufindViewById<
View
>(R.id.
id_view
)
binding.
idView
. Aby to zrobić:
- Usuń definicje zmiennych
editText
inicknameTextView
wraz z ich wywołaniamifindViewById()
. Pojawią się błędy. - Napraw błędy, pobierając widoki
nicknameText
,nicknameEdit
idoneButton
z obiektubinding
zamiast (usuniętych) zmiennych. - Zastąp
view.visibility
wartościąbinding.doneButton.visibility
. Użycie kodubinding.doneButton
zamiast przekazanego koduview
zapewnia spójność kodu.
Uzyskasz taki kod:
binding.nicknameText.text = binding.nicknameEdit.text
binding.nicknameEdit.visibility = View.GONE
binding.doneButton.visibility = View.GONE
binding.nicknameText.visibility = View.VISIBLE
- Nie ma zmian w działaniu tej funkcji. Możesz też wyeliminować parametr
view
i zaktualizować wszystkie zastosowania parametruview
, bybinding.doneButton
korzystały z tej funkcji.
nicknameText
wymagaString
, anicknameEdit.text
toEditable
. Przy wiązaniu danych musisz wyraźnie przekonwertowaćEditable
naString
.
binding.nicknameText.text = binding.nicknameEdit.text.toString()
- Możesz usunąć wyszarzone operacje importowania.
- Połącz funkcję z parametrem
apply{}
.
binding.apply {
nicknameText.text = nicknameEdit.text.toString()
nicknameEdit.visibility = View.GONE
doneButton.visibility = View.GONE
nicknameText.visibility = View.VISIBLE
}
- Utwórz i uruchom swoją aplikację...powinna wyglądać i działać tak samo jak dotychczas.
Dzięki wiązaniu danych możesz udostępniać klasę danych bezpośrednio w widoku danych. Ta metoda upraszcza kod i jest niezwykle przydatna do obsługi bardziej złożonych przypadków.
W tym przykładzie zamiast ustawiać nazwę i pseudonim za pomocą zasobów ciągu znaków, utworzysz klasę danych dla nazwy i pseudonimu. Klasę danych udostępniasz w widoku danych za pomocą wiązania danych.
Krok 1. Utwórz klasę danych MyName
- W Android Studio w katalogu
java
otwórz plikMyName.kt
. Jeśli nie masz tego pliku, utwórz nowy plik Kotlin o nazwieMyName.kt
. - Określ klasę danych dla nazwy i pseudonimu. Użyj pustych ciągów jako wartości domyślnych.
data class MyName(var name: String = "", var nickname: String = "")
Krok 2. Dodaj dane do układu
W pliku activity_main.xml
nazwa jest obecnie ustawiana w TextView
z zasobu ciągu znaków. Musisz zastąpić odwołanie do nazwy odwołaniem do danych w klasie danych.
- Otwórz kartę
activity_main.xml
na karcie Tekst. - U góry układu wstaw tag
<data></data>
, między tagami<layout>
i<LinearLayout>
. Tutaj połączysz widok danych.
<data>
</data>
W tagach danych możesz zadeklarować zmienne nazwane, które zawierają odwołania do klasy.
- Do tagu
<data>
dodaj tag<variable>
. - Dodaj parametr
name
, by nadać zmiennej nazwę"myName"
. Dodaj parametrtype
i ustaw typ na pełną nazwę klasy danychMyName
(nazwa pakietu + nazwa zmiennej).
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
Teraz zamiast używać ciągu znaków jako nazwy możesz wskazać zmienną myName
.
- Zastąp
android:text="@string/name"
poniższym kodem.
@={}
to dyrektywa służąca do pobierania danych, które znajdują się między nawiasami klamrowymi.
myName
odwołuje się do zdefiniowanej wcześniej zmiennej myName
, która wskazuje klasę danych myName
i pobiera z niej właściwość name
.
android:text="@={myName.name}"
Krok 3. Utwórz dane
Masz teraz odwołanie do danych w pliku układu. Następnie utwórz dane.
- Otwórz plik
MainActivity.kt
. - Powyżej
onCreate()
utwórz zmienną prywatną zwaną teżmyName
zgodnie z konwencją. Przypisz zmienną do wystąpienia klasy danychMyName
, przekazując nazwę.
private val myName: MyName = MyName("Aleks Haecky")
- W
onCreate()
ustaw zmiennąmyName
w pliku układu na wartość zadeklarowanej przed chwilą zmiennejmyName
. Nie można uzyskać dostępu bezpośrednio do tej zmiennej w pliku XML. Musisz uzyskać do niego dostęp za pomocą obiektu wiązania.
binding.myName = myName
- Może to powodować błąd, ponieważ po wprowadzeniu zmian musisz odświeżyć obiekt powiązania. Utwórz aplikację, a błąd powinien zniknąć.
Krok 4. Użyj klasy danych dla pseudonimu w TextView
Ostatnim krokiem jest użycie klasy danych pseudonimu w zasadzie TextView
.
- Otwórz aplikację
activity_main.xml
. - W widoku tekstowym
nickname_text
dodaj właściwośćtext
. Odwołuj się do klasynickname
w klasie danych, jak pokazano poniżej.
android:text="@={myName.nickname}"
- W polu
ActivityMain
zastąpnicknameText.text = nicknameEdit.text.toString()
kodem, który ma nadać pseudonim w zmiennejmyName
.
myName?.nickname = nicknameEdit.text.toString()
Po ustawieniu pseudonimu chcesz, aby kod odświeżał interfejs użytkownika za pomocą nowych danych. Aby to zrobić, unieważnij wszystkie wyrażenia wiążące się z odniesieniem do prawidłowych danych.
- Dodaj
invalidateAll()
po ustawieniu pseudonimu, aby interfejs użytkownika został odświeżony przy użyciu wartości ze zaktualizowanego obiektu powiązania.
binding.apply {
myName?.nickname = nicknameEdit.text.toString()
invalidateAll()
...
}
- Utwórz i uruchom swoją aplikację. Powinna ona działać dokładnie tak samo jak dotychczas.
Projekt w Android Studio: AboutMeDataBinding
Instrukcja zastępowania połączeń do findViewById()
:
- Włącz wiązanie danych w sekcji Androida pliku
build.gradle
:dataBinding { enabled = true }
- Użyj
<layout>
jako widoku głównego w układzie XML. - Zdefiniuj zmienną wiązania:
private lateinit var binding: ActivityMainBinding
- Utwórz obiekt wiązania w elemencie
MainActivity
, zastępującsetContentView
:binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
- Zamień wywołania
findViewById()
na odwołania do widoku w obiekcie wiązania. Przykład:findViewById<Button>(R.id.done_button) ⇒ binding.doneBu
tton
(w tym przykładzie nazwa widoku jest tworzona z użyciem wielbłąda na podstawie wartościid
w widoku danych).
Aby powiązać widoki danych z danymi:
- Utwórz klasę danych dla swoich danych.
- Dodaj blok
<data>
wewnątrz tagu<layout>
. - Określ
<variable>
za pomocą nazwy i typu, który jest klasą danych.
<data>
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
</data>
- W
MainActivity
utwórz zmienną z instancją klasy danych. Na przykład:private val myName: MyName = MyName("Aleks Haecky")
- W obiekcie wiązania ustaw zmienną, która właśnie została utworzona:
binding.myName = myName
- W pliku XML ustaw zawartość widoku na zmienną określoną w bloku
<data>
. Aby uzyskać dostęp do danych w klasie danych, użyj kropki.android:text="@={myName.name}"
Kurs Udacity:
Dokumentacja dla programistów Androida:
Ta sekcja zawiera listę możliwych zadań domowych dla uczniów, którzy pracują w ramach tego ćwiczenia w ramach kursu prowadzonego przez nauczyciela. To nauczyciel może wykonać te czynności:
- W razie potrzeby przypisz zadanie domowe.
- Poinformuj uczniów, jak przesyłać zadania domowe.
- Oceń projekty domowe.
Nauczyciele mogą wykorzystać te sugestie tak długo, jak chcą lub chcą, i mogą przypisać dowolne zadanie domowe.
Jeśli samodzielnie wykonujesz te ćwiczenia z programowania, możesz sprawdzić swoją wiedzę w tych zadaniach domowych.
Odpowiedz na te pytania
Pytanie 1
Dlaczego chcesz ograniczyć liczbę bezpośrednich i pośrednich wywołań funkcji findViewById()
?
- Przy każdym wywołaniu
findViewById()
następuje hierarchia widoku. findViewById()
działa w głównym wątku lub interfejsie użytkownika.- Te wywołania mogą spowolnić interfejs użytkownika.
- Jest mniej prawdopodobne, że aplikacja ulegnie awarii.
Pytanie 2
Jak możesz opisać wiązanie danych?
Oto kilka uwag o wiązaniu danych:
- Najważniejszym założeniem wiązania danych jest utworzenie obiektu, który łączy, odnajduje i łączy dwa odległe informacje w czasie kompilacji, dzięki czemu nie trzeba szukać tych danych w czasie działania.
- Obiekt, który wyświetla Ci te powiązania, jest nazywany obiektem wiązania.
- Obiekt powiązania jest tworzony przez kompilator.
Pytanie 3
Która z poniższych przyczyn NIE jest korzyścią z powiązania danych?
- Kod jest krótszy, łatwiejszy do odczytania i łatwiejszy w utrzymaniu.
- Dane i widoki danych są wyraźnie oddzielone.
- Aby uzyskać każdy widok, system Android przechodzi tylko przez hierarchię widoków.
- Wywołanie
findViewById()
powoduje błąd kompilatora. - Zadbaj o bezpieczeństwo, gdy chcesz uzyskać dostęp do widoków.
Pytanie 4
Jaka jest funkcja tagu <layout>
?
- który otacza widok główny w układzie.
- Powiązania są tworzone dla wszystkich widoków układu.
- Wskazuje widok najwyższego poziomu w układzie XML, w którym używane jest wiązanie danych.
- Możesz użyć tagu
<data>
w obrębie znaczników<layout>
, aby powiązać zmienną z klasą danych.
Pytanie 5
Jaki jest prawidłowy sposób odwoływania się do powiązanych danych w układzie XML?
android:text="@={myDataClass.property}"
android:text="@={myDataClass}"
android:text="@={myDataClass.property.toString()}"
android:text="@={myDataClass.bound_data.property}"
Rozpocznij następną lekcję:
Linki do innych ćwiczeń z programowania w tym kursie znajdziesz na stronie docelowej z ćwiczeniami z podstaw Androida Kotlin.