Android Kotlin Fundamentals 06.1: Tworzenie bazy danych Room

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

Większość aplikacji ma dane, które muszą być przechowywane nawet po zamknięciu aplikacji przez użytkownika. Aplikacja może na przykład przechowywać listę odtwarzania, spis elementów w grze, zapisy wydatków i przychodów, katalog konstelacji lub dane dotyczące snu. Do przechowywania trwałych danych zwykle używa się bazy danych.

Room to biblioteka baz danych, która jest częścią Jetpack na Androida. Room wykonuje wiele czynności związanych z konfigurowaniem bazy danych i umożliwia aplikacji interakcję z nią za pomocą zwykłych wywołań funkcji. Room to warstwa abstrakcji nad bazą danych SQLite. Roomi składnia zapytań w przypadku bardziej złożonych zapytań są zgodne z modelem SQLite.

Ilustracja poniżej pokazuje, jak baza danych Room pasuje do ogólnej architektury zalecanej w tym szkoleniu.

Co warto wiedzieć

Musisz znać:

  • Tworzenie podstawowego interfejsu użytkownika (UI) aplikacji na Androida
  • za pomocą aktywności, fragmentów i widoków;
  • przechodzenie między fragmentami i używanie Safe Args (wtyczki Gradle) do przekazywania danych między fragmentami;
  • Wyświetl modele, fabryki modeli widoku i LiveData oraz jego obserwatorów. Te tematy dotyczące komponentów architektury zostały omówione w jednym z wcześniejszych ćwiczeń z programowania w tym kursie.
  • Podstawowa znajomość baz danych SQL i języka SQLite. Szybki przegląd znajdziesz w podstawach SQLite.

Czego się nauczysz

  • jak tworzyć bazę danych Room i z nią wchodzić w interakcje, aby utrwalać dane.
  • Jak utworzyć klasę danych, która definiuje tabelę w bazie danych.
  • Jak używać obiektu dostępu do danych (DAO) do mapowania funkcji Kotlin na zapytania SQL.
  • Jak sprawdzić, czy baza danych działa.

Jakie zadania wykonasz

  • Utwórz bazę danych Room z interfejsem do danych o śnie w nocy.
  • Przetestuj bazę danych za pomocą podanych testów.

W tym ćwiczeniu utworzysz część aplikacji, która śledzi jakość snu. Aplikacja używa bazy danych do przechowywania danych o śnie na przestrzeni czasu.

Aplikacja ma 2 ekrany reprezentowane przez fragmenty, jak pokazano na ilustracji poniżej.

Na pierwszym ekranie (po lewej) znajdują się przyciski rozpoczynania i zatrzymywania śledzenia. Na ekranie wyświetlają się wszystkie dane 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. W aplikacji ocena jest przedstawiana w formie liczbowej. Na potrzeby programowania aplikacja wyświetla zarówno ikony twarzy, jak i ich odpowiedniki liczbowe.

Proces wygląda następująco:

  • Użytkownik otwiera aplikację i widzi ekran śledzenia snu.
  • Użytkownik klika przycisk Rozpocznij. Zapisuje to czas rozpoczęcia i wyświetla go. Przycisk Start jest wyłączony, a przycisk Stop jest włączony.
  • Użytkownik klika przycisk Zatrzymaj. Zapisze to czas zakończenia i otworzy ekran jakości snu.
  • Użytkownik wybiera ikonę jakości snu. Ekran zamyka się, a na ekranie śledzenia wyświetla się godzina zakończenia snu i jego jakość. Przycisk Stop jest wyłączony, a przycisk Start jest włączony. Aplikacja jest gotowa na kolejną noc.
  • Przycisk Wyczyść jest włączony, gdy w bazie danych znajdują się dane. Gdy użytkownik kliknie przycisk Wyczyść, wszystkie jego dane zostaną bezpowrotnie usunięte – nie pojawi się komunikat „Czy na pewno?”.

Ta aplikacja korzysta z uproszczonej architektury, jak pokazano poniżej w kontekście pełnej architektury. Aplikacja korzysta tylko z tych komponentów:

  • kontroler interfejsu,
  • Wyświetl model i LiveData
  • baza danych Room,

Krok 1. Pobierz i uruchom aplikację startową

  1. Pobierz aplikację TrackMySleepQuality-Starter z GitHuba.
  2. Skompiluj i uruchom aplikację. Wyświetli ona interfejs fragmentu SleepTrackerFragment, ale bez danych. Przyciski nie reagują na dotknięcia.

Krok 2. Sprawdź aplikację startową

  1. Przyjrzyj się plikom Gradle:
  • Plik Gradle projektu
     W pliku build.gradle na poziomie projektu zwróć uwagę na zmienne, które określają wersje bibliotek. Wersje użyte w aplikacji startowej dobrze ze sobą współpracują i działają prawidłowo w tej aplikacji. Zanim ukończysz ten kurs, Android Studio może wyświetlić prośbę o zaktualizowanie niektórych wersji. To Ty decydujesz, czy chcesz zaktualizować wersje bibliotek, czy pozostać przy tych, które są w aplikacji. Jeśli napotkasz „dziwne” błędy kompilacji, spróbuj użyć kombinacji wersji bibliotek, których używa aplikacja z ostatecznym rozwiązaniem.
  • Plik Gradle modułu. Zwróć uwagę na podane zależności wszystkich bibliotek Androida Jetpack, w tym Room, oraz zależności dotyczące współprogramów.
  1. Zapoznaj się z pakietami i interfejsem. Aplikacja jest podzielona według funkcji. Pakiet zawiera pliki zastępcze, do których będziesz dodawać kod w ramach tej serii ćwiczeń z programowania.
  • Pakiet database zawierający cały kod związany z bazą danych Room.
  • Pakiety sleepqualitysleeptracker zawierają fragment, model widoku i fabrykę modelu widoku dla każdego ekranu.
  1. Zapoznaj się z Util.ktplikiem, który zawiera funkcje ułatwiające wyświetlanie danych o jakości snu. Niektóre fragmenty kodu są zakomentowane, ponieważ odwołują się do modelu widoku, który utworzysz później.
  2. Zajrzyj do folderu androidTest (SleepDatabaseTest.kt). Ten test pozwoli Ci sprawdzić, czy baza danych działa zgodnie z oczekiwaniami.

W Androidzie dane są reprezentowane w klasach danych, a dostęp do nich i ich modyfikowanie odbywa się za pomocą wywołań funkcji. W bazach danych potrzebne są jednak obiektyzapytania.

  • Jednostka reprezentuje obiekt lub pojęcie oraz jego właściwości, które mają być przechowywane w bazie danych. Klasa encji definiuje tabelę, a każde wystąpienie tej klasy reprezentuje wiersz w tabeli. Każda właściwość definiuje kolumnę. W aplikacji będzie ona przechowywać informacje o nocy snu.
  • Zapytanie to prośba o dane lub informacje z tabeli bazy danych lub kombinacji tabel albo prośba o wykonanie działania na danych. Typowe zapytania służą do pobierania, wstawiania i aktualizowania encji. Możesz na przykład wysłać zapytanie o wszystkie zarejestrowane noce snu posortowane według czasu rozpoczęcia.

Room wykonuje za Ciebie całą ciężką pracę, aby przekształcić klasy danych Kotlin w obiekty, które można przechowywać w tabelach SQLite, a deklaracje funkcji w zapytania SQL.

Każdy obiekt musi być zdefiniowany jako klasa danych z adnotacjami, a interakcje jako interfejs z adnotacjami, czyli obiekt dostępu do danych (DAO). Room używa tych klas z adnotacjami do tworzenia tabel w bazie danych i zapytań, które działają na tej bazie.

Krok 1. Utwórz encję SleepNight

W tym zadaniu zdefiniujesz jedną noc snu jako klasę danych z adnotacjami.

W przypadku jednej nocy snu musisz zarejestrować czas rozpoczęcia i zakończenia snu oraz ocenę jakości.

Potrzebujesz też identyfikatora, który jednoznacznie określa noc.

  1. W pakiecie database znajdź i otwórz plik SleepNight.kt.
  2. Utwórz klasę danych SleepNight z parametrami identyfikatora, czasu rozpoczęcia (w milisekundach), czasu zakończenia (w milisekundach) i oceny jakości snu (wartość liczbowa).
  • Musisz zainicjować zmienną sleepQuality, ustawiając ją na -1, co oznacza, że nie zebrano danych o jakości.
  • Musisz też zainicjować czas zakończenia. Ustaw ją na godzinę rozpoczęcia, aby wskazać, że nie zarejestrowano jeszcze godziny zakończenia.
data class SleepNight(
       var nightId: Long = 0L,
       val startTimeMilli: Long = System.currentTimeMillis(),
       var endTimeMilli: Long = startTimeMilli,
       var sleepQuality: Int = -1
)
  1. Przed deklaracją klasy danych dodaj adnotację do klasy danych za pomocą symbolu @Entity. Nazwij tabelę daily_sleep_quality_table. Argument dla funkcji tableName jest opcjonalny, ale zalecany. Inne argumenty znajdziesz w dokumentacji.

    Jeśli pojawi się odpowiedni komunikat, zaimportuj Entity i wszystkie inne adnotacje z androidx biblioteki.
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(...)
  1. Aby wskazać, że nightId jest kluczem podstawowym, dodaj do właściwości nightId adnotację @PrimaryKey. Ustaw parametr autoGenerate na true, aby Room generował identyfikator dla każdej jednostki. Dzięki temu identyfikator każdej nocy jest unikalny.
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,...
  1. Dodaj adnotacje do pozostałych właściwości za pomocą @ColumnInfo. Dostosuj nazwy właściwości za pomocą parametrów, jak pokazano poniżej.
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(
       @PrimaryKey(autoGenerate = true)
       var nightId: Long = 0L,

       @ColumnInfo(name = "start_time_milli")
       val startTimeMilli: Long = System.currentTimeMillis(),

       @ColumnInfo(name = "end_time_milli")
       var endTimeMilli: Long = startTimeMilli,

       @ColumnInfo(name = "quality_rating")
       var sleepQuality: Int = -1
)
  1. Skompiluj i uruchom kod, aby sprawdzić, czy nie ma w nim błędów.

W tym zadaniu zdefiniujesz obiekt dostępu do danych (DAO). Na Androidzie obiekt DAO udostępnia wygodne metody wstawiania, usuwania i aktualizowania danych w bazie danych.

Gdy używasz Room bazy danych, wysyłasz do niej zapytania, definiując i wywołując w kodzie funkcje Kotlin. Te funkcje w Kotlinie są mapowane na zapytania SQL. Mapowania te definiujesz w obiekcie DAO za pomocą adnotacji, a Room tworzy niezbędny kod.

DAO definiuje niestandardowy interfejs dostępu do bazy danych.

W przypadku typowych operacji na bazie danych biblioteka Room udostępnia wygodne adnotacje, takie jak @Insert, @Delete@Update. W przypadku pozostałych przypadków użyj adnotacji @Query. Możesz napisać dowolne zapytanie obsługiwane przez SQLite.

Dodatkowo podczas tworzenia zapytań w Android Studio kompilator sprawdza, czy nie zawierają one błędów składniowych.

W przypadku bazy danych nocy snu śledzonych przez tracker snu musisz mieć możliwość:

  • Wstaw nowe noce.
  • Zaktualizuj istniejącą noc, aby zmienić godzinę zakończenia i ocenę jakości.
  • Pobieranie konkretnej nocy na podstawie jej klucza.
  • Pobierz wszystkie noce, aby móc je wyświetlać.
  • Uzyskaj najnowsze dane z nocy
  • Usuń wszystkie wpisy w bazie danych.

Krok 1. Utwórz obiekt DAO SleepDatabase

  1. W pakiecie database otwórz SleepDatabaseDao.kt.
  2. Zwróć uwagę, że pole interface SleepDatabaseDao jest oznaczone adnotacją @Dao. Wszystkie obiekty DAO muszą być oznaczone słowem kluczowym @Dao.
@Dao
interface SleepDatabaseDao {}
  1. W treści interfejsu dodaj adnotację @Insert. Pod @Insert dodaj funkcję insert(), która jako argument przyjmuje instancję klasy Entity SleepNight .

    To wszystko. Room wygeneruje cały kod potrzebny do wstawienia SleepNight do bazy danych. Gdy wywołujesz funkcję insert() z kodu Kotlin, Room wykonuje zapytanie SQL, aby wstawić encję do bazy danych. (Uwaga: funkcję możesz nazwać dowolnie).
@Insert
fun insert(night: SleepNight)
  1. Dodaj adnotację @Update z funkcją update() dla jednego SleepNight. Zaktualizowana encja to encja, która ma ten sam klucz co encja przekazana w żądaniu. Możesz zaktualizować niektóre lub wszystkie inne właściwości elementu.
@Update
fun update(night: SleepNight)

W przypadku pozostałych funkcji nie ma wygodnej adnotacji, więc musisz użyć adnotacji @Query i podać zapytania SQLite.

  1. Dodaj adnotację @Query z funkcją get(), która przyjmuje argument Long key i zwraca wartość null SleepNight. Pojawi się błąd dotyczący brakującego parametru.
@Query
fun get(key: Long): SleepNight?
  1. Zapytanie jest przekazywane do adnotacji jako parametr ciągu znaków. Dodaj parametr do @Query. Utwórz String, które będzie zapytaniem SQLite.
  • Wybierz wszystkie kolumny z daily_sleep_quality_table
  • WHERE wartość nightId pasuje do argumentu :key.

    Zwróć uwagę na :key. Aby odwoływać się do argumentów w funkcji, w zapytaniu używaj notacji z dwukropkiem.
("SELECT * from daily_sleep_quality_table WHERE nightId = :key")
  1. Dodaj kolejny @Query z funkcją clear() i zapytaniem SQLite, aby DELETE wszystko z daily_sleep_quality_table. To zapytanie nie powoduje usunięcia samej tabeli.

    Adnotacja @Delete usuwa 1 element. Możesz użyć @Delete i podać listę nocy do usunięcia. Wadą jest to, że musisz pobrać lub znać zawartość tabeli. Adnotacja @Delete świetnie nadaje się do usuwania konkretnych wpisów, ale nie jest skuteczna w przypadku usuwania wszystkich wpisów z tabeli.
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()
  1. Dodaj @Query z funkcją getTonight(). Ustaw wartość zwracaną przez SleepNightgetTonight() jako dopuszczającą wartość null, aby funkcja mogła obsługiwać sytuację, w której tabela jest pusta. (Tabela jest na początku pusta, a po wyczyszczeniu danych).

    Aby uzyskać z bazy danych wartość „tonight”, napisz zapytanie SQLite, które zwraca pierwszy element listy wyników uporządkowanej według pola nightId w kolejności malejącej. Użyj LIMIT 1, aby zwrócić tylko 1 element.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1")
fun getTonight(): SleepNight?
  1. Dodaj @Query z funkcją getAllNights():
  • Spraw, aby zapytanie SQLite zwracało wszystkie kolumny z tabeli daily_sleep_quality_table w kolejności malejącej.
  • Niech getAllNights() zwróci listę SleepNight encji jako LiveData. Room aktualizuje tę LiveData za Ciebie, co oznacza, że musisz pobrać dane tylko raz.
  • Może być konieczne zaimportowanie LiveDataandroidx.lifecycle.LiveData.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC")
fun getAllNights(): LiveData<List<SleepNight>>
  1. Chociaż nie zobaczysz żadnych widocznych zmian, uruchom aplikację, aby upewnić się, że nie zawiera błędów.

W tym zadaniu utworzysz bazę danych Room, która będzie korzystać z obiektu Entity i obiektu DAO utworzonych w poprzednim zadaniu.

Musisz utworzyć abstrakcyjną klasę uchwytu bazy danych z adnotacją @Database. Ta klasa ma jedną metodę, która tworzy instancję bazy danych, jeśli nie istnieje, lub zwraca odwołanie do istniejącej bazy danych.

Uzyskanie bazy danych Room jest nieco skomplikowane, więc zanim zaczniesz pisać kod, zapoznaj się z ogólnym procesem:

  • Utwórz klasę public abstract, która extends RoomDatabase. Ta klasa ma pełnić funkcję kontenera bazy danych. Klasa jest abstrakcyjna, ponieważ Room tworzy dla Ciebie implementację.
  • Dodaj adnotację do zajęć @Database. W argumentach zadeklaruj encje bazy danych i ustaw numer wersji.
  • W obiekcie companion zdefiniuj metodę lub właściwość abstrakcyjną, która zwraca wartość SleepDatabaseDao. Room wygeneruje dla Ciebie treść.
  • W przypadku całej aplikacji wystarczy jedna instancja bazy danych Room, więc ustaw RoomDatabase jako singleton.
  • Użyj narzędzia do tworzenia bazy danych Room, aby utworzyć bazę danych tylko wtedy, gdy nie istnieje. W przeciwnym razie zwróć istniejącą bazę danych.

Krok 1. Utwórz bazę danych

  1. W pakiecie database otwórz SleepDatabase.kt.
  2. W pliku utwórz klasę abstract o nazwie SleepDatabase, która rozszerza klasę RoomDatabase.

    Dodaj do klasy adnotację @Database.
@Database()
abstract class SleepDatabase : RoomDatabase() {}
  1. Pojawi się błąd dotyczący brakujących parametrów elementów i wersji. Adnotacja @Database wymaga kilku argumentów, aby funkcja Room mogła utworzyć bazę danych.
  • Podaj SleepNight jako jedyny element na liście entities.
  • Ustaw wartość version na 1. Po każdej zmianie schematu musisz zwiększyć numer wersji.
  • Ustaw wartość exportSchema na false, aby nie przechowywać kopii zapasowych historii wersji schematu.
entities = [SleepNight::class], version = 1, exportSchema = false
  1. Baza danych musi znać DAO. W treści klasy zadeklaruj wartość abstrakcyjną, która zwraca SleepDatabaseDao. Możesz mieć wiele DAO.
abstract val sleepDatabaseDao: SleepDatabaseDao
  1. Poniżej zdefiniuj obiekt companion. Obiekt towarzyszący umożliwia klientom dostęp do metod tworzenia lub pobierania bazy danych bez tworzenia instancji klasy. Jedynym celem tej klasy jest udostępnianie bazy danych, więc nie ma powodu, aby kiedykolwiek ją tworzyć.
 companion object {}
  1. W obiekcie companion zadeklaruj prywatną zmienną dopuszczającą wartość null INSTANCE dla bazy danych i zainicjuj ją wartością null. Zmienna INSTANCE będzie zawierać odniesienie do bazy danych po jej utworzeniu. Pozwala to uniknąć wielokrotnego otwierania połączeń z bazą danych, co jest kosztowne.

Dodaj adnotację INSTANCE do @Volatile. Wartość zmiennej ulotnej nigdy nie będzie przechowywana w pamięci podręcznej, a wszystkie operacje zapisu i odczytu będą wykonywane w pamięci głównej. Dzięki temu wartość INSTANCE jest zawsze aktualna i taka sama dla wszystkich wątków wykonania. Oznacza to, że zmiany wprowadzone przez jeden wątek w INSTANCE są natychmiast widoczne dla wszystkich innych wątków. Nie dochodzi do sytuacji, w której np. 2 wątki aktualizują to samo pole w pamięci podręcznej, co mogłoby spowodować problem.

@Volatile
private var INSTANCE: SleepDatabase? = null
  1. Poniżej INSTANCE, nadal w obiekcie companion, zdefiniuj getInstance()metodę z parametrem Context, którego będzie potrzebować kreator bazy danych. Zwróć typ SleepDatabase. Pojawi się błąd, ponieważ funkcja getInstance() nie zwraca jeszcze żadnych wyników.
fun getInstance(context: Context): SleepDatabase {}
  1. Wewnątrz getInstance() dodaj blok synchronized{}. Przekaż this, aby uzyskać dostęp do kontekstu.

    Wiele wątków może jednocześnie poprosić o instancję bazy danych, co spowoduje utworzenie dwóch baz danych zamiast jednej. W tej przykładowej aplikacji ten problem raczej nie wystąpi, ale w bardziej złożonej aplikacji jest to możliwe. Umieszczenie kodu w bloku synchronized oznacza, że do tego bloku kodu może wejść tylko jeden wątek wykonania naraz, co gwarantuje, że baza danych zostanie zainicjowana tylko raz.
synchronized(this) {}
  1. Wewnątrz bloku zsynchronizowanego skopiuj bieżącą wartość zmiennej INSTANCE do zmiennej lokalnej instance. Dzięki temu można korzystać z inteligentnego rzutowania, które jest dostępne tylko w przypadku zmiennych lokalnych.
var instance = INSTANCE
  1. Wewnątrz bloku synchronized, return instance na końcu bloku synchronized. Zignoruj błąd niezgodności typu zwracanego. Po zakończeniu nie będziesz zwracać wartości null.
return instance
  1. Nad instrukcją return dodaj instrukcję if, aby sprawdzić, czy instance ma wartość null, czyli czy nie ma jeszcze bazy danych.
if (instance == null) {}
  1. Jeśli instance ma wartość null, użyj kreatora bazy danych, aby ją uzyskać. W treści instrukcji if wywołaj funkcję Room.databaseBuilder i podaj przekazany kontekst, klasę bazy danych oraz nazwę bazy danych, sleep_history_database. Aby usunąć błąd, musisz dodać strategię migracji i build() w kolejnych krokach.
instance = Room.databaseBuilder(
                           context.applicationContext,
                           SleepDatabase::class.java,
                           "sleep_history_database")
  1. Dodaj do narzędzia wymagane strategie migracji. Użyj .fallbackToDestructiveMigration().

    Zwykle musisz podać obiekt migracji ze strategią migracji na wypadek zmiany schematu. Obiekt migracji to obiekt, który określa, jak przekształcić wszystkie wiersze ze starego schematu w wiersze w nowym schemacie, aby nie utracić żadnych danych. Migracja wykracza poza zakres tego ćwiczenia z programowania. Prostym rozwiązaniem jest zniszczenie i ponowne utworzenie bazy danych, co oznacza utratę danych.
.fallbackToDestructiveMigration()
  1. Na koniec zadzwoń .build().
.build()
  1. Przypisz INSTANCE = instance jako ostatni krok w instrukcji if.
INSTANCE = instance
  1. Ostateczny kod powinien wyglądać tak:
@Database(entities = [SleepNight::class], version = 1, exportSchema = false)
abstract class SleepDatabase : RoomDatabase() {

   abstract val sleepDatabaseDao: SleepDatabaseDao

   companion object {

       @Volatile
       private var INSTANCE: SleepDatabase? = null

       fun getInstance(context: Context): SleepDatabase {
           synchronized(this) {
               var instance = INSTANCE

               if (instance == null) {
                   instance = Room.databaseBuilder(
                           context.applicationContext,
                           SleepDatabase::class.java,
                           "sleep_history_database"
                   )
                           .fallbackToDestructiveMigration()
                           .build()
                   INSTANCE = instance
               }
               return instance
           }
       }
   }
}
  1. Skompiluj i uruchom kod.

Masz teraz wszystkie elementy składowe do pracy z bazą danych Room. Ten kod się skompiluje i uruchomi, ale nie będziesz mieć pewności, czy działa prawidłowo. Warto więc dodać kilka podstawowych testów.

Krok 2. Przetestuj bazę danych SleepDatabase

W tym kroku uruchomisz podane testy, aby sprawdzić, czy baza danych działa. Dzięki temu masz pewność, że baza danych działa, zanim zaczniesz ją rozbudowywać. Podane testy są podstawowe. W przypadku aplikacji produkcyjnej należy przetestować wszystkie funkcje i zapytania we wszystkich obiektach DAO.

Aplikacja startowa zawiera folder androidTest. Ten folder androidTest zawiera testy jednostkowe, które obejmują instrumentację Androida. Oznacza to, że testy wymagają platformy Androida, więc musisz je uruchamiać na urządzeniu fizycznym lub wirtualnym. Możesz też tworzyć i uruchamiać czyste testy jednostkowe, które nie korzystają z platformy Androida.

  1. W Android Studio w folderze androidTest otwórz plik SleepDatabaseTest.
  2. Aby odkomentować kod, zaznacz cały zakomentowany kod i naciśnij skrót klawiszowy Cmd+/ lub Control+/.
  3. Sprawdź plik.

Oto szybkie omówienie kodu testowego, ponieważ jest to kolejny fragment kodu, którego możesz użyć ponownie:

  • SleepDabaseTest to klasa testowa.
  • Adnotacja @RunWith identyfikuje program uruchamiający testy, czyli program, który konfiguruje i wykonuje testy.
  • Podczas konfiguracji wykonywana jest funkcja oznaczona adnotacją @Before, która tworzy w pamięci SleepDatabaseSleepDatabaseDao. „W pamięci” oznacza, że ta baza danych nie jest zapisywana w systemie plików i zostanie usunięta po uruchomieniu testów.
  • Podczas tworzenia bazy danych w pamięci kod wywołuje też inną metodę testową, allowMainThreadQueries. Domyślnie, jeśli spróbujesz uruchomić zapytania w głównym wątku, pojawi się błąd. Ta metoda umożliwia przeprowadzanie testów w głównym wątku, co należy robić tylko podczas testowania.
  • W metodzie testowej oznaczonej adnotacją @Test tworzysz, wstawiasz i pobierasz SleepNight oraz sprawdzasz, czy są takie same. Jeśli coś pójdzie nie tak, zgłoś wyjątek. W prawdziwym teście będziesz mieć wiele metod @Test .
  • Po zakończeniu testowania wykonywana jest funkcja oznaczona adnotacją @After, która zamyka bazę danych.
  1. Kliknij prawym przyciskiem myszy plik testowy w panelu Project (Projekt) i wybierz Run 'SleepDatabaseTest' (Uruchom „SleepDatabaseTest”).
  2. Po uruchomieniu testów sprawdź w panelu SleepDatabaseTest, czy wszystkie testy zostały zaliczone.

Wszystkie testy zakończyły się powodzeniem, więc wiesz już kilka rzeczy:

  • Baza danych zostanie utworzona prawidłowo.
  • Możesz wstawić do bazy danych SleepNight.
  • Możesz odzyskać SleepNight.
  • Atrybut SleepNight ma prawidłową wartość jakości.

Projekt Android Studio: TrackMySleepQualityRoomAndTesting

Podczas testowania bazy danych musisz wypróbować wszystkie metody zdefiniowane w obiekcie DAO. Aby zakończyć testowanie, dodaj i wykonaj testy, które będą korzystać z innych metod DAO.

  • Zdefiniuj tabele jako klasy danych oznaczone symbolem @Entity. Zdefiniuj właściwości oznaczone adnotacją @ColumnInfo jako kolumny w tabelach.
  • Zdefiniuj obiekt dostępu do danych (DAO) jako interfejs z adnotacją @Dao. Obiekt DAO mapuje funkcje Kotlin na zapytania do bazy danych.
  • Użyj adnotacji, aby zdefiniować funkcje @Insert, @Delete@Update.
  • W przypadku innych zapytań użyj adnotacji @Query z ciągiem zapytania SQLite jako parametrem.
  • Utwórz klasę abstrakcyjną z funkcją getInstance(), która zwraca bazę danych.
  • Użyj testów z instrumentacją, aby sprawdzić, czy baza danych i obiekt DAO działają zgodnie z oczekiwaniami. Możesz użyć podanych testów jako szablonu.

Kurs Udacity:

Dokumentacja dla deweloperów Androida:

Inne dokumenty i artykuły:

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

How do you indicate that a class represents an entity to store in a Room database?

  • Spraw, aby klasa rozszerzała DatabaseEntity.
  • Dodaj adnotację do zajęć @Entity.
  • Dodaj adnotację do zajęć @Database.
  • Spraw, aby klasa rozszerzała RoomEntity, i dodaj do niej adnotację @Room.

Pytanie 2

Obiekt dostępu do danych (DAO) to interfejs, którego Room używa do mapowania funkcji Kotlin na zapytania do bazy danych.

Jak wskazać, że interfejs reprezentuje obiekt DAO w przypadku bazy danych Room?

  • Spraw, aby interfejs rozszerzał RoomDAO.
  • Spraw, aby interfejs rozszerzał EntityDao, a potem zaimplementuj metodę DaoConnection().
  • Dodaj adnotacje do interfejsu za pomocą @Dao.
  • Dodaj adnotacje do interfejsu za pomocą @RoomConnection.

Pytanie 3

Które z tych stwierdzeń dotyczących Room bazy danych są prawdziwe? Wybierz wszystkie pasujące odpowiedzi.

  • Możesz zdefiniować tabele w bazie danych Room jako klasy danych z adnotacjami.
  • Jeśli zwrócisz LiveData z zapytania, Room będzie aktualizować LiveData, gdy LiveData ulegnie zmianie.
  • Każda baza danych Room musi mieć tylko 1 obiekt DAO.
  • Aby zidentyfikować klasę jako Room bazę danych, ustaw ją jako podklasę RoomDatabase i dodaj do niej adnotację @Database.

Pytanie 4

Których z tych adnotacji możesz używać w @Dao? Wybierz wszystkie pasujące odpowiedzi.

  • @Get
  • @Update
  • @Insert
  • @Query

Pytanie 5

Jak sprawdzić, czy baza danych działa? Zaznacz wszystkie pasujące opcje.

  • pisanie testów z użyciem instrumentacji,
  • Kontynuuj pisanie i uruchamianie aplikacji, aż wyświetli ona dane.
  • Zastąp wywołania metod w interfejsie DAO wywołaniami równoważnych metod w klasie Entity.
  • Uruchom funkcję verifyDatabase() udostępnianą przez bibliotekę Room.

Przejdź do następnej lekcji: 6.2 Korutyny i Room

Linki do innych ćwiczeń z tego kursu znajdziesz na stronie docelowej ćwiczeń z podstaw języka Kotlin na Androidzie.