Seitendaten erfassen

Dieses Handbuch baut auf der Paging Library auf und besprechen, wie Sie Passen Sie die Lösung zum Laden von Daten an Ihre App-Architektur an. Anforderungen.

Beobachtbare Liste erstellen

Normalerweise beobachtet der UI-Code eine LiveData<PagedList>-Objekt (oder Wenn Sie RxJava2 verwenden, Flowable<PagedList>- oder Observable<PagedList>-Objekt), das sich in Ihrem ViewModel der App Dieses beobachtbares Objekt stellt eine Verbindung zwischen der Präsentation und dem Inhalt der die Listendaten Ihrer App.

Um eine dieser beobachtbaren PagedList-Objekten übergeben, übergeben Sie Instanz von DataSource.Factory bis ein LivePagedListBuilder oder RxPagedListBuilder -Objekt enthält. Ein DataSource-Objekt wird geladen. Seiten für eine einzelne PagedList. Die Factory-Klasse erstellt neue Instanzen von PagedList als Reaktion auf Inhaltsaktualisierungen wie Entwertungen von Datenbanktabellen und Netzwerkaktualisierungen. Die Raumpersistenz Library kann DataSource.Factory bereitstellen. Objekte für Sie zu erstellen oder eigene zu erstellen.

Im folgenden Code-Snippet sehen Sie, wie eine neue Instanz LiveData<PagedList> in Ihrem ViewModel-Klasse der App mithilfe von Raum DataSource.Factory-Gebäude Funktionen:

Logo: Concertdao

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

Konzertansicht

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

Eigene Paging-Konfiguration definieren

Um eine weitere Konfiguration LiveData<PagedList> für Fortgeschrittene können Sie Ihre eigene Paging-Konfiguration definieren. Insbesondere können Sie folgende Attribute festlegen:

  • Seitengröße: Die Anzahl der Elemente auf jeder Seite.
  • Prefetch-Entfernung: Angesichts des letzten sichtbaren Elements in der Benutzeroberfläche einer App ist die Anzahl der Elemente darüber hinaus Element, das die Paging Library im Voraus abrufen sollte. Dieser Wert um ein Vielfaches größer als die Seitengröße sein.
  • Platzhalter vorhanden: Bestimmt, ob in der Benutzeroberfläche Platzhalter für Listenelemente angezeigt werden, für die keine noch nicht vollständig geladen ist. Für eine Diskussion über die Vor- und Nachteile der Verwendung von finden Sie unter Platzhalter in Ihrem UI:

Wenn Sie genauer steuern möchten, wann die Seitenbibliothek eine Liste aus Ihrem Anwendungsdatenbank, übergeben Sie eine benutzerdefinierte Executor-Objekt in der LivePagedListBuilder, Dies wird im folgenden Code-Snippet gezeigt:

Konzertansicht

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

Richtigen Typ der Datenquelle auswählen

Es ist wichtig, eine Verbindung zu der Datenquelle herzustellen, die Ihre Quelle am besten verarbeitet Datenstruktur:

  • Verwenden Sie PageKeyedDataSource wenn Seiten, die du lädst, die Schlüssel zum Einbetten von „Weiter“ und „Zurück“. Wenn Sie z. B. soziale Netzwerke aus dem Netzwerk gepostet haben, musst du möglicherweise ein nextPage-Token von einem in einen nachfolgenden Ladevorgang geladen werden.
  • Verwenden Sie ItemKeyedDataSource wenn müssen Sie Daten aus Element N verwenden, um Element N+1 abzurufen. Wenn Sie beispielsweise Kommentare mit Unterhaltungsthreads für eine Diskussions-App abrufen, müssen Sie möglicherweise die ID des letzten Kommentars ein, um den Inhalt des nächsten zu erhalten.
  • Verwenden Sie PositionalDataSource wenn Sie müssen Seiten mit Daten von einem beliebigen Speicherort abrufen, den Sie in Ihrem Datenspeicher auswählen. Diese Klasse unterstützt die Anforderung eines Satzes von Datenelementen, beginnend mit einem beliebigen Standort auswählen. Die Anfrage könnte beispielsweise die 50 Datenelemente zurückgeben, beginnend mit Standort 1500.

Benachrichtigen, wenn Daten ungültig sind

Wenn Sie die Paging-Bibliothek verwenden, muss der Nutzer über die Datenschicht benachrichtigt werden. oder andere Ebenen Ihrer Anwendung erstellt, wenn eine Tabelle oder Zeile veraltet ist. Rufen Sie dazu unter invalidate() von Ihren Kurs DataSource die Sie für Ihre App ausgewählt haben.

Eigene Datenquellen erstellen

Wenn Sie eine benutzerdefinierte lokale Datenlösung verwenden oder Daten direkt aus einer können Sie eines der Abgeleitete DataSource-Klassen. Die Das folgende Code-Snippet zeigt eine Datenquelle, die vom Beginn:

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

Sie können diese benutzerdefinierten Daten dann in PagedList-Objekte laden, indem Sie ein konkrete Unterklasse von DataSource.Factory Die Das folgende Code-Snippet zeigt, wie neue Instanzen der benutzerdefinierten Daten generiert werden. Quelle, die im vorherigen Code-Snippet definiert wurde:

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

Überdenken, wie Inhaltsaktualisierungen funktionieren

Wenn Sie beobachtbare PagedList-Objekten enthält, sollten Sie sich überlegen, und Inhaltsaktualisierungen funktionieren. Wenn Sie Daten direkt aus einem Raum Datenbankaktualisierungen werden an die Benutzeroberfläche deiner App gesendet. automatisch.

Bei Verwendung einer Paged Network API erfolgt normalerweise eine Nutzerinteraktion, z. B. „Zum Aktualisieren wischen“, als Signal für die Entwertung des Am häufigsten verwendete DataSource vor Kurzem. Anschließend fordern Sie eine neue Instanz dieser Datenquelle an. Folgendes Code-Snippet dieses Verhalten veranschaulicht:

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

Datenabgleich bereitstellen

Die Paging Library unterstützt artikel- und seitenbasierte Transformationen von Elementen. von DataSource geladen.

Im folgenden Code-Snippet wird eine Kombination aus Konzertname und Konzertdatum ist einem einzelnen String zugeordnet, der sowohl den Namen als auch das Datum enthält:

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

Dies kann nützlich sein, wenn Sie Elemente nach der Erstellung verpacken, konvertieren oder vorbereiten möchten. geladen. Da diese Arbeit mit dem Fetch-Executor durchgeführt wird, können Sie potenziell wie das Lesen von Daten von der Festplatte oder das Abfragen einer separaten Datenbank.

Feedback geben

Wir freuen uns über dein Feedback und deine Ideen:

Problemverfolgung
Melde Probleme, damit wir sie beheben können.

Weitere Informationen

Weitere Informationen zur Paging Library finden Sie in der in den folgenden Ressourcen.

Produktproben

Codelabs

Videos