Ten przewodnik opiera się na bibliotece stron internetowych omówię, w którym znajdziesz dostosować rozwiązanie do ładowania danych do architektury aplikacji do Twoich potrzeb.
Utwórz listę dostrzegalną
Zwykle w kodzie interfejsu użytkownika występują:
LiveData<PagedList>
(lub
w przypadku używania RxJava2,
Flowable<PagedList>
lub Observable<PagedList>
), który znajduje się w
ViewModel
aplikacji. Ten
dostrzegalny obiekt tworzy połączenie między prezentacją a treścią
danych o listach aplikacji.
Aby utworzyć jedną z tych obserwowalnych
PagedList
, przekaż
wystąpienie
DataSource.Factory
do
LivePagedListBuilder
lub RxPagedListBuilder
obiektu. Wczyta się obiekt DataSource
stron dla pojedynczej wartości PagedList
. Klasa fabryczna tworzy nowe instancje
PagedList
w odpowiedzi na aktualizacje treści, takie jak unieważnienia tabel bazy danych
i odświeżania sieci. Trwałość sal
biblioteka może zapewnić DataSource.Factory
Możesz też utworzyć własny.
Fragment kodu poniżej pokazuje, jak utworzyć nowe wystąpienie
LiveData<PagedList>
w:
zajęcia ViewModel
w aplikacji za pomocą
Sala
DataSource.Factory
-kompilacja
funkcje:
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> }
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(); }
Kotlin
// The Int type argument corresponds to a PositionalDataSource object. val myConcertDataSource : DataSource.Factory<Int, Concert> = concertDao.concertsByDate() val concertList = myConcertDataSource.toLiveData(pageSize = 50)
Java
// The Integer type argument corresponds to a PositionalDataSource object. DataSource.Factory<Integer, Concert> myConcertDataSource = concertDao.concertsByDate(); LiveData<PagedList<Concert>> concertList = LivePagedListBuilder(myConcertDataSource, /* page size */ 50).build();
Definiowanie własnej konfiguracji stronicowania
Aby bardziej szczegółowo skonfigurować
LiveData<PagedList>
– zaawansowane
możesz też zdefiniować własną konfigurację stronicowania. Możesz na przykład:
zdefiniować następujące atrybuty:
- Rozmiar strony: Liczba elementów na każdej stronie.
- Odległość pobierania z wyprzedzeniem: Biorąc pod uwagę ostatni widoczny element w interfejsie aplikacji, liczba elementów poza tym ostatnim element, który biblioteka stronowa powinna próbować pobrać z wyprzedzeniem. Ta wartość powinien być kilkakrotnie większy od rozmiaru strony.
- Obecność zastępcza: Określa, czy w interfejsie wyświetlane są zmienne dla elementów listy, które nie zawierają . Omówimy zalety i wady stosowania Dowiedz się, jak umieszczać obiekty zastępcze w Google Analytics.
Jeśli chcesz mieć większą kontrolę nad tym, kiedy biblioteka stron internetowych wczytuje listę z
do bazy danych aplikacji, przekazywać niestandardowe
Executor
w tabeli
LivePagedListBuilder
,
Jak widać w tym fragmencie kodu:
Kotlin
val myPagingConfig = Config( pageSize = 50, prefetchDistance = 150, enablePlaceholders = true ) // The Int type argument corresponds to a PositionalDataSource object. val myConcertDataSource : DataSource.Factory<Int, Concert> = concertDao.concertsByDate() val concertList = myConcertDataSource.toLiveData( pagingConfig = myPagingConfig, fetchExecutor = myExecutor )
Java
PagedList.Config myPagingConfig = new PagedList.Config.Builder() .setPageSize(50) .setPrefetchDistance(150) .setEnablePlaceholders(true) .build(); // The Integer type argument corresponds to a PositionalDataSource object. DataSource.Factory<Integer, Concert> myConcertDataSource = concertDao.concertsByDate(); LiveData<PagedList<Concert>> concertList = new LivePagedListBuilder<>(myConcertDataSource, myPagingConfig) .setFetchExecutor(myExecutor) .build();
Wybór odpowiedniego typu źródła danych
Ważne jest połączenie ze źródłem danych, które najlepiej go obsługuje struktura danych:
- Używaj
PageKeyedDataSource
, jeśli wczytywane strony, umieść klawisze następny/poprzedni. Na przykład, jeśli pobierasz dane z mediów społecznościowych, postów w mediach społecznościowych z sieci, konieczne może być przekazanie tokenanextPage
z jednego do kolejnego wczytywania. - Używaj
ItemKeyedDataSource
, jeśli musisz użyć danych z elementu N, aby pobrać element N+1. Jeśli na przykład pobierasz komentarze z wątkami w przypadku aplikacji do dyskusji, konieczne może być przekazanie identyfikatora od ostatniego komentarza, aby pobrać zawartość następnego. - Używaj
PositionalDataSource
, jeśli możesz pobierać strony z danymi z dowolnej lokalizacji, którą wybierzesz w magazynie danych. Ta klasa obsługuje żądania zbioru elementów danych zaczynających się od dowolnej lokalizację. Żądanie może na przykład zwrócić 50 elementów danych zaczynając od lokalizacji 1500.
Powiadamiaj o nieprawidłowych danych
W przypadku korzystania z biblioteki stronicowania warstwa danych ma obowiązek powiadamiać
w innych warstwach aplikacji, gdy tabela lub wiersz stają się nieaktualne. Aby to zrobić, zadzwoń:
invalidate()
z
DataSource
zajęcia, które masz
wybrane dla Twojej aplikacji.
Tworzenie własnych źródeł danych
Jeśli używasz niestandardowego rozwiązania do obsługi danych lokalnych lub wczytujesz dane bezpośrednio z
możesz zastosować jedną z funkcji
DataSource
.
następujący fragment kodu wskazuje źródło danych powiązane z
godzina rozpoczęcia:
Kotlin
class ConcertTimeDataSource() : ItemKeyedDataSource<Date, Concert>() { override fun getKey(item: Concert) = item.startTime override fun loadInitial( params: LoadInitialParams<Date>, callback: LoadInitialCallback<Concert>) { val items = fetchItems(params.requestedInitialKey, params.requestedLoadSize) callback.onResult(items) } override fun loadAfter( params: LoadParams<Date>, callback: LoadCallback<Concert>) { val items = fetchItemsAfter( date = params.key, limit = params.requestedLoadSize) callback.onResult(items) } }
Java
public class ConcertTimeDataSource extends ItemKeyedDataSource<Date, Concert> { @NonNull @Override public Date getKey(@NonNull Concert item) { return item.getStartTime(); } @Override public void loadInitial(@NonNull LoadInitialParams<Date> params, @NonNull LoadInitialCallback<Concert> callback) { List<Concert> items = fetchItems(params.key, params.requestedLoadSize); callback.onResult(items); } @Override public void loadAfter(@NonNull LoadParams<Date> params, @NonNull LoadCallback<Concert> callback) { List<Concert> items = fetchItemsAfter(params.key, params.requestedLoadSize); callback.onResult(items); }
Następnie możesz wczytać te dostosowane dane do obiektów PagedList
, tworząc
konkretny podklasa
DataSource.Factory
ten fragment kodu pokazuje, jak generować nowe wystąpienia danych niestandardowych
źródła zdefiniowanego w poprzednim fragmencie kodu:
Kotlin
class ConcertTimeDataSourceFactory : DataSource.Factory<Date, Concert>() { val sourceLiveData = MutableLiveData<ConcertTimeDataSource>() var latestSource: ConcertDataSource? override fun create(): DataSource<Date, Concert> { latestSource = ConcertTimeDataSource() sourceLiveData.postValue(latestSource) return latestSource } }
Java
public class ConcertTimeDataSourceFactory extends DataSource.Factory<Date, Concert> { private MutableLiveData<ConcertTimeDataSource> sourceLiveData = new MutableLiveData<>(); private ConcertDataSource latestSource; @Override public DataSource<Date, Concert> create() { latestSource = new ConcertTimeDataSource(); sourceLiveData.postValue(latestSource); return latestSource; } }
Zastanów się, jak działają aktualizacje treści
Podczas tworzenia modułu dostrzegalnego
PagedList
, zobacz, jak
i aktualizacje treści. Jeśli wczytujesz dane bezpośrednio z pokoju
aktualizacje bazy danych są przekazywane do interfejsu aplikacji
automatycznie.
Korzystając z interfejsu API sieci z pozycją na stronach, zwykle występuje interakcja z użytkownikiem, na przykład:
„przesuń, aby odświeżyć”, są sygnałem do unieważnienia
DataSource
, z których korzystasz najczęściej
w ostatnim czasie. Następnie wysyłasz prośbę o nowe wystąpienie tego źródła danych. Obserwujący
fragment kodu ilustruje takie działanie:
Kotlin
class ConcertActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { // ... concertTimeViewModel.refreshState.observe(this, Observer { // Shows one possible way of triggering a refresh operation. swipeRefreshLayout.isRefreshing = it == MyNetworkState.LOADING }) swipeRefreshLayout.setOnRefreshListener { concertTimeViewModel.invalidateDataSource() } } } class ConcertTimeViewModel(firstConcertStartTime: Date) : ViewModel() { val dataSourceFactory = ConcertTimeDataSourceFactory(firstConcertStartTime) val concertList: LiveData<PagedList<Concert>> = dataSourceFactory.toLiveData( pageSize = 50, fetchExecutor = myExecutor ) fun invalidateDataSource() = dataSourceFactory.sourceLiveData.value?.invalidate() }
Java
public class ConcertActivity extends AppCompatActivity { @Override public void onCreate(@Nullable Bundle savedInstanceState) { // ... viewModel.getRefreshState() .observe(this, new Observer<NetworkState>() { // Shows one possible way of triggering a refresh operation. @Override public void onChanged(@Nullable MyNetworkState networkState) { swipeRefreshLayout.isRefreshing = networkState == MyNetworkState.LOADING; } }; swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshListener() { @Override public void onRefresh() { viewModel.invalidateDataSource(); } }); } } public class ConcertTimeViewModel extends ViewModel { private LiveData<PagedList<Concert>> concertList; private DataSource<Date, Concert> mostRecentDataSource; public ConcertTimeViewModel(Date firstConcertStartTime) { ConcertTimeDataSourceFactory dataSourceFactory = new ConcertTimeDataSourceFactory(firstConcertStartTime); mostRecentDataSource = dataSourceFactory.create(); concertList = new LivePagedListBuilder<>(dataSourceFactory, 50) .setFetchExecutor(myExecutor) .build(); } public void invalidateDataSource() { mostRecentDataSource.invalidate(); } }
Dodaj mapowanie danych
Biblioteka stron docelowych obsługuje przekształcanie elementów na podstawie elementów i stron
wczytany przez DataSource
.
W poniższym fragmencie kodu połączenie nazwy koncertu i daty koncertu to mapowane na jeden ciąg zawierający zarówno nazwę, jak i datę:
Kotlin
class ConcertViewModel : ViewModel() { val concertDescriptions : LiveData<PagedList<String>> init { val concerts = database.allConcertsFactory() .map { "${it.name} - ${it.date}" } .toLiveData(pageSize = 50) } }
Java
public class ConcertViewModel extends ViewModel { private LiveData<PagedList<String>> concertDescriptions; public ConcertViewModel(MyDatabase database) { DataSource.Factory<Integer, Concert> factory = database.allConcertsFactory().map(concert -> concert.getName() + "-" + concert.getDate()); concertDescriptions = new LivePagedListBuilder<>( factory, /* page size */ 50).build(); } }
Jest to przydatne, jeśli chcesz pakować, przekonwertować lub przygotować produkty po ich wczytano. Ponieważ operacja jest wykonywana na wykonawcy pobierania, możesz potencjalnie kosztowną pracę, taką jak odczyt z dysku lub wykonywanie zapytań do oddzielnej bazy danych.
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
- Omówienie biblioteki Paging 2
- Wyświetlaj listy stronicowane