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:
Koncert Dao
@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>
}
@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();
}
Model widoku koncertu
// The Int type argument corresponds to a PositionalDataSource object.
val myConcertDataSource : DataSource.Factory<Int, Concert> =
concertDao.concertsByDate()
val concertList = myConcertDataSource.toLiveData(pageSize = 50)
// 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:
Model widoku koncertu
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
)
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:
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)
}
}
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:
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
}
}
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:
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()
}
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ę:
class ConcertViewModel : ViewModel() {
val concertDescriptions : LiveData<PagedList<String>>
init {
val concerts = database.allConcertsFactory()
.map { "${it.name} - ${it.date}" }
.toLiveData(pageSize = 50)
}
}
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
Obecnie nie ma rekomendacji.
Zaloguj się na swoje konto Google.