Omówienie biblioteki Paging 2 Zawiera Android Jetpack.
Biblioteka stron internetowych pomaga wczytywać i wyświetlać jednocześnie małe porcje danych. Wczytywanie częściowych danych na żądanie zmniejsza wykorzystanie przepustowości sieci i systemu i zasobami Google Cloud.
W tym przewodniku zawarto kilka przykładowych zastosowań biblioteki, a także jak to działa. Aby zobaczyć pełne przykłady, jak ta biblioteka , wypróbuj ćwiczenia w Codelabs i przykłady z dodatkowych .
Konfiguracja
Aby zaimportować komponenty stronicowania do aplikacji na Androida, dodaj te elementy
zależności od pliku build.gradle
aplikacji:
Odlotowe
dependencies { def paging_version = "2.1.2" implementation "androidx.paging:paging-runtime:$paging_version" // For Kotlin use paging-runtime-ktx // alternatively - without Android dependencies for testing testImplementation "androidx.paging:paging-common:$paging_version" // For Kotlin use paging-common-ktx // optional - RxJava support implementation "androidx.paging:paging-rxjava2:$paging_version" // For Kotlin use paging-rxjava2-ktx }
Kotlin
dependencies { val paging_version = "2.1.2" implementation("androidx.paging:paging-runtime:$paging_version") // For Kotlin use paging-runtime-ktx // alternatively - without Android dependencies for testing testImplementation("androidx.paging:paging-common:$paging_version") // For Kotlin use paging-common-ktx // optional - RxJava support implementation("androidx.paging:paging-rxjava2:$paging_version") // For Kotlin use paging-rxjava2-ktx }
Architektura bibliotek
W tej sekcji opisano i przedstawiliśmy główne komponenty biblioteki stronicowania.
Lista z podziałem na strony
Kluczowym komponentem biblioteki stron docelowych jest
PagedList
, która się wczytuje
fragmenty danych o aplikacji, czy strony. Wraz ze wzrostem ilości potrzebnych danych
stronę do istniejącego obiektu PagedList
. Jeśli jakieś wczytane dane ulegną zmianie, zostanie utworzony nowy
wystąpienie PagedList
jest wysyłane do obserwowalnego posiadacza danych z
LiveData
lub obiekt oparty na RxJava2. Jako
Liczba wygenerowanych obiektów: PagedList
,
interfejs aplikacji prezentuje jej zawartość z poszanowaniem
cykle życia.
Poniższy fragment kodu pokazuje, jak skonfigurować model widoku danych w aplikacji
wczytuj i prezentuj dane za pomocą posiadacza LiveData
obiektów PagedList
:
Kotlin
class ConcertViewModel(concertDao: ConcertDao) : ViewModel() { val concertList: LiveData<PagedList<Concert>> = concertDao.concertsByDate().toLiveData(pageSize = 50) }
Java
public class ConcertViewModel extends ViewModel { private ConcertDao concertDao; public final LiveData<PagedList<Concert>> concertList; // Creates a PagedList object with 50 items per page. public ConcertViewModel(ConcertDao concertDao) { this.concertDao = concertDao; concertList = new LivePagedListBuilder<>( concertDao.concertsByDate(), 50).build(); } }
Dane
Wczytuje się każde wystąpienie instancji PagedList
aktualnego podsumowania danych o aplikacji z odpowiadających im
DataSource
. Przepływy danych
z backendu lub bazy danych aplikacji do obiektu PagedList
.
W przykładzie poniżej użyto funkcji Trwałość sal lub bibliotekido porządkowania danych aplikacji. Jeśli chcesz przechowywać dane w inny sposób, możesz udostępnić własne dane, fabrykę źródeł.
Kotlin
@Dao interface ConcertDao { // The Int type parameter tells Room to use a PositionalDataSource object. @Query("SELECT * FROM concerts ORDER BY date DESC") fun concertsByDate(): DataSource.Factory<Int, Concert> }
Java
@Dao public interface ConcertDao { // The Integer type parameter tells Room to use a // PositionalDataSource object. @Query("SELECT * FROM concerts ORDER BY date DESC") DataSource.Factory<Integer, Concert> concertsByDate(); }
Więcej informacji o wczytywaniu danych do obiektów PagedList
znajdziesz tutaj:
dowiesz się, jak wczytywać dane stronicowane.
Interfejs użytkownika
Zajęcia w PagedList
współpracują z
PagedListAdapter
, aby wczytać elementy do
RecyclerView
Te
razem podczas pobierania i wyświetlania treści
lub animowanie treści.
Więcej informacji znajdziesz w przewodniku Wyświetlanie stron .
Obsługa różnych architektur danych
Biblioteka stron internetowych obsługuje te architektury danych:
- Udostępniane tylko z serwera backendu.
- Są przechowywane tylko w bazie danych na urządzeniu.
- Kombinacja innych źródeł wykorzystująca bazę danych na urządzeniu jako pamięć podręczną.
Rysunek 1 pokazuje przepływ danych w każdym z tych scenariuszy dotyczących architektury. W w przypadku rozwiązania obejmującego tylko sieć lub tylko bazę danych dane przepływają bezpośrednio do do modelu jej interfejsu. Jeśli stosujesz podejście łączone, przepływy danych do bazy danych na urządzeniu, a potem do modelu interfejsu aplikacji. Co jakiś czas w punkcie końcowym przepływu danych brakuje danych do wczytania. żąda wtedy więcej danych od komponentu, który je dostarczył. Gdy na przykład w bazie danych na urządzeniu kończą się dane, żąda ona więcej danych z serwera.
W pozostałej części tej sekcji znajdziesz zalecenia dotyczące konfiguracji każdego i przypadku użycia przepływu danych.
Tylko sieć
Aby wyświetlić dane z serwera backendu, użyj synchronicznej wersji interfejsu API
Retrofit API do załadowania
informacje do własnych danych DataSource
.
Tylko baza danych
Skonfiguruj urządzenie RecyclerView
w celu obserwacji pamięci lokalnej, najlepiej stosując funkcję trwałości sal
. Dzięki temu zawsze, gdy dane
są wstawione lub zmodyfikowane w bazie danych aplikacji, zmiany te są automatycznie
RecyclerView
, w którym są wyświetlane te dane.
Sieć i baza danych
Po rozpoczęciu obserwowania bazy danych możesz nasłuchiwać, gdy
w bazie danych brakuje danych za pomocą funkcji
PagedList.BoundaryCallback
Następnie możesz pobrać więcej elementów ze swojej sieci i wstawić je do
w bazie danych. Jeśli interfejs użytkownika obserwuje bazę danych, to wystarczy.
Obsługa błędów sieci
Jeśli korzystasz z sieci do pobierania lub strony wyświetlanych danych za pomocą nie należy traktować sieci jako „dostępny” lub „niedostępny” przez cały czas, ponieważ wiele połączeń jest przerywanych lub niepewne:
- Konkretny serwer może nie odpowiedzieć na żądanie sieciowe.
- Urządzenie może być połączone z siecią, która jest wolna lub słaba.
Zamiast tego aplikacja powinna sprawdzać każdą prośbę pod kątem błędów i przywracać jak najbardziej bezproblemowo, gdy sieć jest niedostępna. Przykład: możesz spróbować ponownie, przycisk, który pozwala użytkownikom wybrać, czy krok odświeżenia danych nie działa. Jeśli podczas stronicowania danych wystąpi błąd, spróbuj ponownie żądania stronicowania.
Aktualizowanie istniejącej aplikacji
Jeśli aplikacja korzysta już z danych z bazy danych lub źródła backendu, możliwość bezpośredniego przejścia na funkcje dostępne w bibliotece stronicowania. Z tej sekcji dowiesz się, jak uaktualnić aplikację, która ma taki sam typowy wygląd.
Niestandardowe rozwiązania stronicowania
Jeśli używasz funkcji niestandardowych do wczytywania niewielkich podzbiorów danych ze strony
źródła danych, możesz zastąpić tę logikę tą z zbioru danych
PagedList
. Instancje
Usługa PagedList
ma wbudowane połączenia z często używanymi źródłami danych. Te instancje
a także adaptery
RecyclerView
obiektów, które
które da się umieścić w interfejsie aplikacji.
Dane wczytywane z użyciem list zamiast stron
Jeśli jako zapasowej struktury danych interfejsu użytkownika używasz listy w pamięci
adaptera, rozważ obserwację aktualizacji danych za pomocą
PagedList
, jeśli liczba
Liczba elementów na liście może osiągnąć duży rozmiar. Instancje PagedList
mogą używać:
LiveData<PagedList>
lub
Observable<List>
, aby przekazywać aktualizacje danych do interfejsu aplikacji, co minimalizuje czas wczytywania
i wykorzystanie pamięci. Jeszcze lepiej, jeśli zastąpisz List
z obiektem PagedList
w aplikacji nie wymaga żadnych zmian
strukturę interfejsu aplikacji
lub funkcje aktualizacji danych.
Powiąż kursor danych z widokiem listy za pomocą CursorAdapter
Aplikacja może korzystać z CursorAdapter
aby powiązać dane z Cursor
ListView
. W takim przypadku zazwyczaj trzeba
aby przeprowadzić migrację z ListView
do
RecyclerView
jako
kontener interfejsu listy aplikacji, a następnie zastąp Cursor
z komponentem Sala lub
PositionalDataSource
w zależności od tego, czy instancje Cursor
mają dostęp do
SQLite.
W niektórych sytuacjach, na przykład podczas pracy z wystąpieniami
Spinner
, dostarczasz tylko przejściówkę
Biblioteka pobiera dane wczytane do adaptera,
wyświetla dane za Ciebie. W takiej sytuacji zmień typ pliku
danych adaptera do
LiveData<PagedList>
, a następnie zawijaj
tę listę w obiekcie ArrayAdapter
przed próbą użycia klasy biblioteki w zwiększaniu tych elementów w interfejsie.
Asynchroniczne ładowanie treści przy użyciu narzędzia AsyncListUtil
Jeśli używasz
AsyncListUtil
obiektów do
umożliwia asynchroniczne ładowanie i wyświetlanie grup informacji,
możesz łatwiej ładować dane:
- Dane nie muszą decydować o pozycji. Biblioteka stronnicza umożliwia wczytywanie bezpośrednio z backendu za pomocą kluczy udostępnianych przez sieć.
- Ilość danych może być niepoliczalna. Za pomocą biblioteki stronicowania można wczytać dane na stronach do momentu, gdy nie będą dostępne żadne dane.
- Możesz łatwiej obserwować dane. Biblioteka stronnicza może prezentować: przechowywane przez model ViewModel aplikacji w obserwalnej strukturze danych.
Przykłady baz danych
Poniższe fragmenty kodu pokazują kilka możliwych sposobów utworzenia wszystkich nad ich współpracą.
Obserwacja danych podzielonych na strony przy użyciu LiveData
Fragment kodu poniżej przedstawia współdziałanie wszystkich elementów. Jako koncert
zdarzenia w bazie danych zostały dodane, usunięte lub zmienione w bazie danych,
RecyclerView
to
można aktualizować automatycznie i skutecznie:
Kotlin
@Dao interface ConcertDao { // The Int type parameter tells Room to use a PositionalDataSource // object, with position-based loading under the hood. @Query("SELECT * FROM concerts ORDER BY date DESC") fun concertsByDate(): DataSource.Factory<Int, Concert> } class ConcertViewModel(concertDao: ConcertDao) : ViewModel() { val concertList: LiveData<PagedList<Concert>> = concertDao.concertsByDate().toLiveData(pageSize = 50) } class ConcertActivity : AppCompatActivity() { public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Use the 'by viewModels()' Kotlin property delegate // from the activity-ktx artifact val viewModel: ConcertViewModel by viewModels() val recyclerView = findViewById(R.id.concert_list) val adapter = ConcertAdapter() viewModel.concertList.observe(this, PagedList(adapter::submitList)) recyclerView.setAdapter(adapter) } } class ConcertAdapter() : PagedListAdapter<Concert, ConcertViewHolder>(DIFF_CALLBACK) { fun onBindViewHolder(holder: ConcertViewHolder, position: Int) { val concert: Concert? = getItem(position) // Note that "concert" is a placeholder if it's null. holder.bindTo(concert) } companion object { private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Concert>() { // Concert details may have changed if reloaded from the database, // but ID is fixed. override fun areItemsTheSame(oldConcert: Concert, newConcert: Concert) = oldConcert.id == newConcert.id override fun areContentsTheSame(oldConcert: Concert, newConcert: Concert) = oldConcert == newConcert } } }
Java
@Dao public interface ConcertDao { // The Integer type parameter tells Room to use a PositionalDataSource // object, with position-based loading under the hood. @Query("SELECT * FROM concerts ORDER BY date DESC") DataSource.Factory<Integer, Concert> concertsByDate(); } public class ConcertViewModel extends ViewModel { private ConcertDao concertDao; public final LiveData<PagedList<Concert>> concertList; public ConcertViewModel(ConcertDao concertDao) { this.concertDao = concertDao; concertList = new LivePagedListBuilder<>( concertDao.concertsByDate(), /* page size */ 50).build(); } } public class ConcertActivity extends AppCompatActivity { @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); ConcertViewModel viewModel = new ViewModelProvider(this).get(ConcertViewModel.class); RecyclerView recyclerView = findViewById(R.id.concert_list); ConcertAdapter adapter = new ConcertAdapter(); viewModel.concertList.observe(this, adapter::submitList); recyclerView.setAdapter(adapter); } } public class ConcertAdapter extends PagedListAdapter<Concert, ConcertViewHolder> { protected ConcertAdapter() { super(DIFF_CALLBACK); } @Override public void onBindViewHolder(@NonNull ConcertViewHolder holder, int position) { Concert concert = getItem(position); if (concert != null) { holder.bindTo(concert); } else { // Null defines a placeholder item - PagedListAdapter automatically // invalidates this row when the actual object is loaded from the // database. holder.clear(); } } private static DiffUtil.ItemCallback<Concert> DIFF_CALLBACK = new DiffUtil.ItemCallback<Concert>() { // Concert details may have changed if reloaded from the database, // but ID is fixed. @Override public boolean areItemsTheSame(Concert oldConcert, Concert newConcert) { return oldConcert.getId() == newConcert.getId(); } @Override public boolean areContentsTheSame(Concert oldConcert, Concert newConcert) { return oldConcert.equals(newConcert); } }; }
Obserwacja danych stronicowanych za pomocą RxJava2
Jeśli wolisz używać
RxJava2 zamiast
LiveData
, możesz zamiast tego
utwórz obiekt Observable
lub Flowable
:
Kotlin
class ConcertViewModel(concertDao: ConcertDao) : ViewModel() { val concertList: Observable<PagedList<Concert>> = concertDao.concertsByDate().toObservable(pageSize = 50) }
Java
public class ConcertViewModel extends ViewModel { private ConcertDao concertDao; public final Observable<PagedList<Concert>> concertList; public ConcertViewModel(ConcertDao concertDao) { this.concertDao = concertDao; concertList = new RxPagedListBuilder<>( concertDao.concertsByDate(), /* page size */ 50) .buildObservable(); } }
Następnie możesz rozpocząć i przestać obserwować dane, korzystając z kodu w następujący sposób: snippet:
Kotlin
class ConcertActivity : AppCompatActivity() { private val adapter = ConcertAdapter() // Use the 'by viewModels()' Kotlin property delegate // from the activity-ktx artifact private val viewModel: ConcertViewModel by viewModels() private val disposable = CompositeDisposable() public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val recyclerView = findViewById(R.id.concert_list) recyclerView.setAdapter(adapter) } override fun onStart() { super.onStart() disposable.add(viewModel.concertList .subscribe(adapter::submitList))) } override fun onStop() { super.onStop() disposable.clear() } }
Java
public class ConcertActivity extends AppCompatActivity { private ConcertAdapter adapter = new ConcertAdapter(); private ConcertViewModel viewModel; private CompositeDisposable disposable = new CompositeDisposable(); @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); RecyclerView recyclerView = findViewById(R.id.concert_list); viewModel = new ViewModelProvider(this).get(ConcertViewModel.class); recyclerView.setAdapter(adapter); } @Override protected void onStart() { super.onStart(); disposable.add(viewModel.concertList .subscribe(adapter.submitList(flowableList) )); } @Override protected void onStop() { super.onStop(); disposable.clear(); } }
Kody ConcertDao
i ConcertAdapter
są takie same dla
Oparta na RxJava2
jak w przypadku
rozwiązanie oparte na LiveData
.
Prześlij opinię
Podziel się z nami swoimi opiniami i pomysłami, korzystając z tych zasobów:
- Narzędzie do śledzenia błędów
- Zgłoś problemy, abyśmy mogli je naprawić.
Dodatkowe materiały
Więcej informacji o bibliotece stronicowania znajdziesz w poniższe zasoby.
Próbki
Ćwiczenia z programowania
Filmy
- Android Jetpack: zarządzaj nieskończonymi listami za pomocą funkcji RecyclerView i Paging (Google I/O 2018)
- Android Jetpack: stronicowanie
Polecane dla Ciebie
- Uwaga: tekst linku wyświetla się, gdy JavaScript jest wyłączony
- Migracja do Paging 3
- Wyświetlaj listy stronicowane
- Zbieranie danych według stron