Gromadzenie danych z podziałem na strony

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

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();
}

Model widoku koncertu

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:

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

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 tokena nextPage 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

. .