Database Views With Room for Android

Room jest warstwą abstrakcji nad SQLite, którą Google zapakował jako bibliotekę AndroidX, a także poleca. Od wersji 2.1, Room oferuje możliwość dodawania widoków bazy danych, znanych również jako przechowywane zapytania.

Niektóre z dobrych powodów do używania widoków bazy danych to:

  • Ułatwiają one pisanie złożonych zapytań i używanie ich w zapytaniach Data Access Object (DAO).
  • Możesz pytać tylko o te pola, których potrzebujesz, zamiast przeglądać wszystkie pola w tabeli.

W tym poradniku zbudujesz aplikację Customer Surveys, która pozwala klientom restauracji zostawiać opinie, a następnie zapisuje te opinie w zarządzanej bazie danych Room. Podczas tego procesu nauczysz się następujących rzeczy:

  • Co to jest Widok Bazy Danych?
  • Jak tworzyć Widoki Bazy Danych?
  • Jak używać ich do uproszczenia pisania zapytań SELECT
Uwaga: Ten samouczek zakłada, że masz doświadczenie w tworzeniu aplikacji dla Androida w Kotlinie i pracowałeś już z programem Room. Jeśli nie jesteś zaznajomiony z Roomem, spójrz na nasz tutorial Data Persistence with Room.

Tutorial ten używa również Coroutines z Roomem. Aby dowiedzieć się więcej, przeczytaj nasz tutorial Coroutines With Room Persistence Library.

Rozpoczęcie

Pobierz projekt startowy klikając przycisk Pobierz materiały na górze lub na dole tego tutoriala.

Wyodrębnij plik ZIP i otwórz projekt startowy w Android Studio 4.0 lub nowszym wybierając Otwórz istniejący projekt Android Studio na ekranie powitalnym.

Po zakończeniu synchronizacji Gradle, zbadaj strukturę projektu. Projekt jest zgodny z architekturą MVVM, więc podobne funkcjonalności znajdują się w jednym pakiecie. Zapoznaj się z obecnymi pakietami – będziesz ich używał w tym tutorialu.

Zbuduj i uruchom. Zobaczysz prosty ekran z wiadomością powitalną, obrazkiem i przyciskiem START SURVEY.

Ekran startowy aplikacji Customer Surveys

Tknij przycisk START SURVEY. Na potrzeby tego poradnika możesz zignorować fakt, że nie jadłeś posiłku w restauracji :]

Kolejnym ekranem jest ekran ankiety. Posiada on pole do wpisania maila, przyciski radiowe do wyboru posiłku, który oceniasz oraz trzy pytania. Każde pytanie ma pod sobą przyciski Dobra, Średnia i Zła, więc użytkownik może ocenić swoją satysfakcję.

Ekran ankiety aplikacji Customer Surveys z pytaniami i możliwymi ocenami

Zobaczysz także przycisk PRZEŚLIJ ANKIETĘ. Dotknij go, a zobaczysz toast, który mówi, że jeszcze nie czas na wypełnienie ankiety. Nie martw się, naprawisz to w trakcie tego samouczka.

Teraz zostałeś powitany w restauracji The View, gdzie będziesz mógł zobaczyć niesamowite widoki natury, spróbować ich pysznych posiłków i ocenić swoje zadowolenie. W tym czasie, dowiesz się również o widokach bazy danych Room.

Używanie widoków bazy danych

Pomyśl o tabeli, która ma dodatkową funkcjonalność wstępnie spakowanych zapytań SELECT dla wygody. Room w wersji 2.1 i wyższej nazywa je widokiem bazy danych i zapewnia adnotację o tej samej nazwie, tj. @DatabaseView.

Używając tej adnotacji możesz oznaczyć klasę, aby zachowywała się jak Widok Bazy Danych. Umożliwi to dołączenie zapytania do klasy, jak poniżej:

@DatabaseView("SELECT user.id, user.name " + "AS departmentName FROM user " + "WHERE user.departmentId = department.id")class User { var id: Long = 0 var name: String? = null}

Możesz następnie użyć tej klasy w DAO do zapytania o dane w taki sam sposób, w jaki zrobiłbyś to z klasą oznaczoną jako Entity, np. Tabela w bazie danych.

A DAO pomaga uzyskać dostęp do danych z bazy danych Twojej aplikacji. Zazwyczaj zawiera metody CUD (Create, Update i Delete) i może również zawierać inne metody, które mogą być niezbędne do odczytu i zapisu danych w bazie danych.

Zależność między widokami bazy danych a bazą danych jest podobna do zależności między encjami a bazą danych. Przyjrzymy się bliżej tym relacjom w następnej części.

Porównanie widoku bazy danych i encji

Klasy z adnotacją @DatabaseView są podobne do klas Entity. Oto jak:

  • Obydwie mogą używać SELECT FROM w zapytaniach DAO.
  • Database Views i Entitys mogą zarówno używać @ColumnInfo, co pozwala na dostosowanie informacji o kolumnach związanych z polem.
  • Obydwie mogą używać @Embedded, co pozwala polu mieć zagnieżdżone pola, do których zapytania mogą się bezpośrednio odwoływać.

Pomimo że istnieje wiele podobieństw między nimi, istnieją również różnice między DatabaseViews i Entitys:

  • Możesz używać INSERT, UPDATE i DELETE z Entity, ale nie z DatabaseView.
  • Wszystkie widoki w swoich aplikacjach definiujesz za pomocą views, ale encje definiujesz za pomocą entities.

Teraz, gdy już wiesz, czym jest DatabaseView i jak porównuje się i kontrastuje z klasą Entity, nadszedł czas, aby z niej skorzystać i rozpocząć składanie ankiety dla The View Restaurant.

Przesłanie ankiety

Pierwszym krokiem jest dodanie logiki do przesłania ankiety i zapisania jej do bazy danych Room po dotknięciu przycisku SUBMIT SURVEY.

Przejdź do customersurveys/CustomerSurveyFragment.kt, gdzie dodasz logikę do zbierania odpowiedzi i zapisywania ich do Room. Zrób to, zastępując kod w submitSurvey() tym:

// 1val email = editEmail.text.toString()// 2if (validateEmail(email)) { // 3 val meal = when (radioGroupMeals.checkedRadioButtonId) { R.id.radioBreakfast -> "Breakfast" R.id.radioLunch -> "Lunch" R.id.radioDinner -> "Dinner" else -> "No Meal" } // 4 val customerSurvey = SurveyListItem .CustomerSurvey(0, email, meal, questionOneAnswer, questionTwoAnswer, questionThreeAnswer) customerSurveyViewModel.insertCustomerSurvey(customerSurvey) // 5 findNavController() .navigate(R.id.action_surveyFragment_to_surveyCompletedFragment)}

Oto, co robisz z tym kodem:

  1. Pobierasz e-mail z editEmail i przypisujesz go do zmiennej: email.
  2. Ta kontrola warunku wywołuje validateEmail(email), która sprawdza, czy email jest null, czy nie. Zwraca false, jeśli jest to null. Sprawdza również, czy wprowadzony e-mail jest ważny i zwraca false, jeśli nie jest.
  3. Kod wewnątrz instrukcji if wykonuje się, gdy validateEmail(email) zwróci true. meal przechowuje typ posiłku, który użytkownik wybrał z grup radiowych.
  4. Gdy mamy już wartość meal, tworzymy SurveyListItem.CustomerSurvey, który zawiera wszystkie informacje o ankiecie. Pobiera ona wartości dla questionOneAnswer, questionTwoAnswer i questionThreeAnswer z toggleButtonListeners(), który ma do tego celu listenery.
  5. Tutaj zapisujesz customerSurvey poprzez wywołanie insertCustomerSurvey(customerSurvey) w CustomerSurveyViewModel, który obsługuje logikę zapisu do Room.
  6. Prowadzisz nawigację do SurveyCompletedFragment.

Po dodaniu tego zauważysz, że customerSurveyViewModel i findNavController() mają czerwone podkreślenia. Aby to naprawić, najpierw dodaj inicjalizację CustomerSurveyViewModel na górze klasy, tuż pod inicjalizacją questionThreeAnswer.

private val customerSurveyViewModel: CustomerSurveyViewModel by viewModels()

Upewnij się, że dodałeś odpowiednie deklaracje importu, gdy IDE Cię o to poprosi.

Zbuduj i uruchom. Uruchom ankietę, wprowadź wymagane dane e-mail i wybierz odpowiedzi na pytania.

Ekran ankiety z odpowiedziami

Wspaniale, ukończyłeś ankietę.

Przeglądaj wszystkie ankiety używając widoku bazy danych Zrzut ekranu

Tknij przycisk PRZEGLĄDAJ ANKIETY… ups, to jeszcze nic nie robi. Nie martw się, wkrótce to naprawisz.

W następnym rozdziale dowiesz się, jak stworzyć swój pierwszy DatabaseView.

Tworzenie widoku bazy danych

Aby utworzyć widok, dodasz adnotację @DatabaseView do klasy lub klasy danych. Zacznij od nawigacji do customersurveys/SurveyListItem.kt. Jest to zamknięta klasa z kilkoma klasami danych, których możesz użyć w tym tutorialu.

Na dole SurveyListItem, tuż poniżej QuestionOneSadView, dodaj następujące elementy:

data class HappyBreakFastView( override val email: String) : SurveyListItem()

Ta klasa danych nadpisuje zmienną email z SurveyListItem i dziedziczy po klasie – co oznacza, że jest podtypem SurveyListItem.

Po utworzeniu tej klasy danych, dodaj @DatabaseView z zapytaniem SELECT, aby pobrać wszystkie identyfikatory email z tabeli CustomerSurvey, gdzie posiłek jest ustawiony na „Śniadanie”, tuż nad klasą danych HappyBreakFastView. Twoja adnotacja powinna wyglądać tak:

@DatabaseView("SELECT CustomerSurvey.email FROM CustomerSurvey WHERE CustomerSurvey.meal = 'Breakfast'")

Kilka rzeczy do odnotowania na temat zapytania wewnątrz adnotacji:

  • Zapytanie działa jak każde inne zapytanie, które napisałeś w Room.
  • Potrzebujesz zażądać wszystkich pól, które masz w swojej klasie danych podczas pisania zapytania. W tym przypadku, potrzebujesz tylko email. Używasz SELECT CustomerSurvey.email From..., aby uzyskać email z CustomerSurvey.
Uwaga: W tym tutorialu, trzymasz widoki i encje wewnątrz SurveyListItem, aby uniknąć powtórzeń i ułatwić czytanie kodu. Nie zawsze musisz podklasować swoje widoki w zamkniętej klasie; mogą one również znajdować się w osobnym pliku lub klasie.

Gratulacje, stworzyłeś swój pierwszy widok! Następnie zobaczysz, jak możesz użyć widoku w swoich zapytaniach DAO.

Używanie widoków bazy danych pokoju w zapytaniach DAO

Po pierwsze, włączysz HappyBreakFastView do views w @Database aplikacji.

Przejdź do database/AppDatabase.kt i, wewnątrz views, dodaj SurveyListItem.HappyBreakFastView::class. Twoja zaktualizowana adnotacja @Database powinna wyglądać jak poniżej:

@Database(entities = , version = 2, exportSchema = false, views = )

Zauważ, że version = 2. Musisz zaktualizować wersję bazy danych za każdym razem, gdy dodajesz view w AppDatabase – w przeciwnym razie twoja aplikacja się zawiesi. W tym przypadku zaktualizowałeś wersję do 2. Zsynchronizuj gradle, aby zastosować wszystkie te zmiany.

Następnie przejdź do customers/CustomerSurveysDao.kt i, tuż poniżej getQuestionOneSadView(), dodaj następujący kod:

@Query("SELECT * FROM HappyBreakFastView")fun getHappyBreakFastCustomers():LiveData<List<SurveyListItem.HappyBreakFastView>>

Ta metoda pobiera z restauracji wszystkich klientów, którzy byli zadowoleni z jakiegokolwiek aspektu ankiety. Aby wyjaśnić to bardziej szczegółowo:

  • Po pierwsze, używasz HappyBreakFastView tak jak w normalnym zapytaniu.
  • Wywołujesz tę metodę w CustomerSurveyRepo, aby uzyskać listę wszystkich klientów, którzy odpowiedzieli na którekolwiek z pytań z wartością Good. Zauważ, że typem zwrotnym metody jest lista LiveData typu SurveyListItem.HappyBreakFastView, która jest obserwowalnym uchwytem zmiennej.

Teraz utworzyłeś view i metodę do zapytania o listę klientów, którzy odpowiedzieli pozytywnie w CustomerSurveysDao. W następnym rozdziale dowiesz się, jak wywołać tę metodę z klasy repozytorium.

Pobieranie danych przy użyciu DatabaseView

Przejdź do customersurveys/CustomerSurveyRepo.kt i dodaj następującą metodę tuż pod getQuestionOneSadView():

fun getHappyBreakFastCustomers() : LiveData<List<SurveyListItem.HappyBreakFastView>> { return customerSurveysDao.getHappyBreakFastCustomers()}

Ta metoda wywołuje getHappyBreakFastCustomers() z CustomerSurveysDao, aby pobrać dane z Room. Jej typem zwrotnym jest LiveData, co pozwala wywołującemu tę metodę obserwować wszelkie zmiany w danych.

Następnie w CustomerSurveyViewModel dodasz wywołanie do getHappyBreakFastCustomers(). Odpowiada ona za wyświetlanie danych do widoku – którym w tym przypadku nie jest DatabaseView, lecz AllSurveysFragment.

Navigate to customersurveys/CustomerSurveyViewModel.kt and add the following code:

val happyBreakfastCustomers : LiveData<List<SurveyListItem.HappyBreakFastView>> by lazy { customerSurveyRepo.getHappyBreakFastCustomers()}

Ta zmienna dostaje swoją wartość przez wywołanie getHappyBreakFastCustomers() z CustomerSurveyRepo. Jest tam by lazy{}, aby nie ładować danych natychmiast, ale raczej przy pierwszym dostępie do zmiennej.

Następnie zaktualizujesz UI, aby mógł wyświetlić dane.

Wyświetlanie danych w UI

Nawiguj do allsurveys/AllSurveysFragment.kt i dodaj następujący kod na dole klasy:

private fun getHappyBreakfastCustomers() { customerSurveyViewModel.happyBreakfastCustomers.observe(viewLifecycleOwner, Observer { customerSurveyList -> if (customerSurveyList.isEmpty()) { layoutEmptyView.visibility = View.VISIBLE rvReviews.visibility = View.GONE } else { layoutEmptyView.visibility = View.GONE rvReviews.visibility = View.VISIBLE initView(customerSurveyList) } })}private fun initView(customerSurveySurveyList: List<SurveyListItem.HappyBreakFastView>) { val customerSurveysAdapter = CustomerSurveysAdapter(customerSurveySurveyList) rvReviews.adapter = customerSurveysAdapter}

W celu wyjaśnienia, co robi ten kod:

  • Po pierwsze, wywołuje happyBreakfastCustomers i obserwuje jego wartość.
  • Wewnątrz lambdy observe, jest sprawdzenie, czy customerSurveyList jest null czy nie. Jeśli lista jest null, ustawiamy komunikat TextView’No surveys found! na visible i ukrywamy RecyclerView. Jeśli nie jest to null, to ustawiamy widoczność TextView na GONE i pokazujemy RecyclerView. Wywołujesz również initView(customerSurveyList) z wartością customerSurveyList z CustomerSurveyViewModel.
  • initView(customerSurveySurveyList: List) inicjalizuje CustomerSurveysAdapter za pomocą customerSurveyList i ustawia adapter dla RecyclerView na CustomerSurveysAdapter, który teraz wyświetla listę ankiet do UI.

IDE wyświetli monit o dodanie importu SurveyListItem. Jeśli tak się nie stanie, dodaj ten import:

import com.raywenderlich.android.customersurveys.customersurveys.SurveyListItem

Po wyświetleniu danych w interfejsie użytkownika musisz wykonać jeszcze tylko kilka kroków, aby wszystko działało idealnie.

Następnie dodasz kod, który obsługuje pobieranie danych z Sali w zależności od opcji wybranej na rozwijanej liście w interfejsie użytkownika, tj. widżecie Spinner.

Pobieranie danych dla różnych widoków

Dodaj następujący fragment kodu tuż poniżej onCreate w AllSurveysFragment.kt::

private fun spinnerListener() { filterSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onNothingSelected(parent: AdapterView<*>?) {} override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { when (position) { 0 -> resetState() 1 -> getAllCustomerSurveys() 2 -> getHappyBreakfastCustomers() 3 -> getSadDinnerCustomers() 4 -> getAverageLunchCustomers() 5 -> getQuestionOneSadCustomers() } } }}

Powyższy fragment kodu ustawia onItemSelectedListener na filterSpinner i nadpisuje dwie metody: onNothingSelected i onItemSelected. Nie chcesz nic robić, gdy nic nie jest wybrane, więc onNothingSelected pozostaje puste. Chcesz jednak reagować na wybranie elementu, więc musisz zaimplementować onItemSelected.

onItemSelected ma wyrażenie when, które wywołuje różne metody w zależności od opcji wybranej w filterSpinner. Metody te są podobne do getHappyBreakfastCustomers(), ale pobierają dane przy użyciu innego DatabaseView.

Upewnij się, że dodajesz import, gdy IDE o to poprosi.

Na koniec dodaj wywołanie do spinnerListener() wewnątrz onViewCreated, zaraz po setupSpinner(), jak pokazano poniżej:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setupSpinner() // Added spinnerListener()}

Teraz, gdy masz już wszystko gotowe do pobierania ankiet, następnym krokiem jest dodanie kodu do nawigacji do AllSurveysFragment.

Nawigacja do wszystkich ankiet

To jest ostatni krok, którego potrzebujesz, aby zobaczyć widoki w akcji.

Nawiguj do completedsurvey/SurveyCompletedFragment.kt i odkomentuj kod wewnątrz btnViewSurveys. Twój wynik końcowy będzie wyglądał tak:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) btnViewSurveys.setOnClickListener { findNavController() .navigate(R.id.action_surveyCompletedFragment_to_allSurveysFragment) }}

Tutaj po prostu ustawiasz słuchacza kliknięć dla przycisku VIEW SURVEYS i przechodzisz do AllSurveysFragment.

Po odkomentowaniu kodu, IDE wyświetli monit o zaimportowanie findNavController(). Po prostu zaimportuj wymagane.

Zbuduj, uruchom i rozpocznij ankietę, następnie odpowiedz na pytania i wyślij je. Na koniec wyświetl Wszystkie ankiety, gdzie będziesz mógł pobrać wszystkie dane w zależności od opcji, którą wybrałeś na spinnerze.

Opcje spinnera w aplikacji
Lista średnio zadowolonych klientów przy użyciu widoku bazy danych
Lista niezadowolonych klientów przy użyciu widoku bazy danych

Gratulacje! Zakończyłeś swoje doświadczenie w The View Restaurant. Mamy nadzieję, że zjadłeś wspaniały posiłek, zobaczyłeś niesamowite widoki i miałeś szansę dowiedzieć się czym są DatabaseViews.

Where to Go From Here?

Pobierz końcowy projekt używając przycisku Download Materials na górze lub na dole tutoriala.

Aby uzyskać więcej informacji na temat funkcji Room’a, sprawdź oficjalną dokumentację z Androida.

Mamy nadzieję, że podobał Ci się ten tutorial Widoki bazy danych Room. Jeśli masz jakieś pytania, komentarze lub niesamowite modyfikacje do tego projektu aplikacji, proszę dołącz do dyskusji na forum poniżej.

raywenderlich.com Weekly

Biuletyn raywenderlich.com jest najprostszym sposobem, aby być na bieżąco ze wszystkim, co musisz wiedzieć jako deweloper mobilny.

Zdobądź cotygodniowy skrót naszych samouczków i kursów, a jako bonus otrzymasz darmowy, dogłębny kurs e-mailowy!

Średnia ocena

4.8/5

Add a rating for this content

Sign in to add a rating

10 ratings

.

Leave a Reply