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
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.
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ę.
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 View
s iEntity
s 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 DatabaseView
s i Entity
s:
- Możesz używać INSERT, UPDATE i DELETE z
Entity
, ale nie zDatabaseView
. - 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:
- Pobierasz e-mail z
editEmail
i przypisujesz go do zmiennej:email
. - Ta kontrola warunku wywołuje
validateEmail(email)
, która sprawdza, czy email jestnull
, czy nie. Zwracafalse
, jeśli jest tonull
. Sprawdza również, czy wprowadzony e-mail jest ważny i zwracafalse
, jeśli nie jest. - Kod wewnątrz instrukcji
if
wykonuje się, gdyvalidateEmail(email)
zwrócitrue
.meal
przechowuje typ posiłku, który użytkownik wybrał z grup radiowych. - Gdy mamy już wartość
meal
, tworzymySurveyListItem.CustomerSurvey
, który zawiera wszystkie informacje o ankiecie. Pobiera ona wartości dlaquestionOneAnswer
,questionTwoAnswer
iquestionThreeAnswer
ztoggleButtonListeners()
, który ma do tego celu listenery. - Tutaj zapisujesz
customerSurvey
poprzez wywołanieinsertCustomerSurvey(customerSurvey)
wCustomerSurveyViewModel
, który obsługuje logikę zapisu do Room. - 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.
Wspaniale, ukończyłeś ankietę.
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 zCustomerSurvey
.
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 listaLiveData
typuSurveyListItem.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 jestnull
, ustawiamy komunikatTextView
’No surveys found! na visible i ukrywamyRecyclerView
. Jeśli nie jest tonull
, to ustawiamy widocznośćTextView
na GONE i pokazujemyRecyclerView
. Wywołujesz równieżinitView(customerSurveyList)
z wartościącustomerSurveyList
zCustomerSurveyViewModel
. -
initView(customerSurveySurveyList: List)
inicjalizujeCustomerSurveysAdapter
za pomocącustomerSurveyList
i ustawia adapter dlaRecyclerView
naCustomerSurveysAdapter
, 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.
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
.
Leave a Reply