/* * Copyright 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package androidx.paging; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.arch.core.util.Function; import java.util.List; import java.util.concurrent.Executor; /** * Incremental data loader for paging keyed content, where loaded content uses previously loaded * items as input to future loads. *
* Implement a DataSource using ItemKeyedDataSource if you need to use data from item {@code N - 1} * to load item {@code N}. This is common, for example, in sorted database queries where * attributes of the item such just before the next query define how to execute it. *
* The {@code InMemoryByItemRepository} in the
* PagingWithNetworkSample
* shows how to implement a network ItemKeyedDataSource using
* Retrofit, while
* handling swipe-to-refresh, network errors, and retry.
*
* @param
* Note that this key is generally a hint, and may be ignored if you want to always load
* from the beginning.
*/
@Nullable
public final Key requestedInitialKey;
/**
* Requested number of items to load.
*
* Note that this may be larger than available data.
*/
public final int requestedLoadSize;
/**
* Defines whether placeholders are enabled, and whether the total count passed to
* {@link LoadInitialCallback#onResult(List, int, int)} will be ignored.
*/
public final boolean placeholdersEnabled;
public LoadInitialParams(@Nullable Key requestedInitialKey, int requestedLoadSize,
boolean placeholdersEnabled) {
this.requestedInitialKey = requestedInitialKey;
this.requestedLoadSize = requestedLoadSize;
this.placeholdersEnabled = placeholdersEnabled;
}
}
/**
* Holder object for inputs to {@link #loadBefore(LoadParams, LoadCallback)}
* and {@link #loadAfter(LoadParams, LoadCallback)}.
*
* @param
* Returned data must begin directly adjacent to this position.
*/
public final Key key;
/**
* Requested number of items to load.
*
* Returned page can be of this size, but it may be altered if that is easier, e.g. a
* network data source where the backend defines page size.
*/
public final int requestedLoadSize;
public LoadParams(Key key, int requestedLoadSize) {
this.key = key;
this.requestedLoadSize = requestedLoadSize;
}
}
/**
* Callback for {@link #loadInitial(LoadInitialParams, LoadInitialCallback)}
* to return data and, optionally, position/count information.
*
* A callback can be called only once, and will throw if called again.
*
* If you can compute the number of items in the data set before and after the loaded range,
* call the three parameter {@link #onResult(List, int, int)} to pass that information. You
* can skip passing this information by calling the single parameter {@link #onResult(List)},
* either if it's difficult to compute, or if {@link LoadInitialParams#placeholdersEnabled} is
* {@code false}, so the positioning information will be ignored.
*
* It is always valid for a DataSource loading method that takes a callback to stash the
* callback and call it later. This enables DataSources to be fully asynchronous, and to handle
* temporary, recoverable error states (such as a network error that can be retried).
*
* @param
* Call this method from your DataSource's {@code loadInitial} function to return data,
* and inform how many placeholders should be shown before and after. If counting is cheap
* to compute (for example, if a network load returns the information regardless), it's
* recommended to pass data back through this method.
*
* It is always valid to pass a different amount of data than what is requested. Pass an
* empty list if there is no more data to load.
*
* @param data List of items loaded from the DataSource. If this is empty, the DataSource
* is treated as empty, and no further loads will occur.
* @param position Position of the item at the front of the list. If there are {@code N}
* items before the items in data that can be loaded from this DataSource,
* pass {@code N}.
* @param totalCount Total number of items that may be returned from this DataSource.
* Includes the number in the initial {@code data} parameter
* as well as any items that can be loaded in front or behind of
* {@code data}.
*/
public abstract void onResult(@NonNull List
* A callback can be called only once, and will throw if called again.
*
* It is always valid for a DataSource loading method that takes a callback to stash the
* callback and call it later. This enables DataSources to be fully asynchronous, and to handle
* temporary, recoverable error states (such as a network error that can be retried).
*
* @param
* Call this method from your ItemKeyedDataSource's
* {@link #loadBefore(LoadParams, LoadCallback)} and
* {@link #loadAfter(LoadParams, LoadCallback)} methods to return data.
*
* Call this from {@link #loadInitial(LoadInitialParams, LoadInitialCallback)} to
* initialize without counting available data, or supporting placeholders.
*
* It is always valid to pass a different amount of data than what is requested. Pass an
* empty list if there is no more data to load.
*
* @param data List of items loaded from the ItemKeyedDataSource.
*/
public abstract void onResult(@NonNull List
* This method is called first to initialize a PagedList with data. If it's possible to count
* the items that can be loaded by the DataSource, it's recommended to pass the loaded data to
* the callback via the three-parameter
* {@link LoadInitialCallback#onResult(List, int, int)}. This enables PagedLists
* presenting data from this source to display placeholders to represent unloaded items.
*
* {@link LoadInitialParams#requestedInitialKey} and {@link LoadInitialParams#requestedLoadSize}
* are hints, not requirements, so they may be altered or ignored. Note that ignoring the
* {@code requestedInitialKey} can prevent subsequent PagedList/DataSource pairs from
* initializing at the same location. If your data source never invalidates (for example,
* loading from the network without the network ever signalling that old data must be reloaded),
* it's fine to ignore the {@code initialLoadKey} and always start from the beginning of the
* data set.
*
* @param params Parameters for initial load, including initial key and requested size.
* @param callback Callback that receives initial load data.
*/
public abstract void loadInitial(@NonNull LoadInitialParams
* It's valid to return a different list size than the page size if it's easier, e.g. if your
* backend defines page sizes. It is generally safer to increase the number loaded than reduce.
*
* Data may be passed synchronously during the loadAfter method, or deferred and called at a
* later time. Further loads going down will be blocked until the callback is called.
*
* If data cannot be loaded (for example, if the request is invalid, or the data would be stale
* and inconsistent, it is valid to call {@link #invalidate()} to invalidate the data source,
* and prevent further loading.
*
* @param params Parameters for the load, including the key to load after, and requested size.
* @param callback Callback that receives loaded data.
*/
public abstract void loadAfter(@NonNull LoadParams
* It's valid to return a different list size than the page size if it's easier, e.g. if your
* backend defines page sizes. It is generally safer to increase the number loaded than reduce.
*
* Note: Data returned will be prepended just before the key
* passed, so if you vary size, ensure that the last item is adjacent to the passed key.
*
* Data may be passed synchronously during the loadBefore method, or deferred and called at a
* later time. Further loads going up will be blocked until the callback is called.
*
* If data cannot be loaded (for example, if the request is invalid, or the data would be stale
* and inconsistent, it is valid to call {@link #invalidate()} to invalidate the data source,
* and prevent further loading.
*
* @param params Parameters for the load, including the key to load before, and requested size.
* @param callback Callback that receives loaded data.
*/
public abstract void loadBefore(@NonNull LoadParams
* If your ItemKeyedDataSource is loading from a source that is sorted and loaded by a unique
* integer ID, you would return {@code item.getID()} here. This key can then be passed to
* {@link #loadBefore(LoadParams, LoadCallback)} or
* {@link #loadAfter(LoadParams, LoadCallback)} to load additional items adjacent to the item
* passed to this function.
*
* If your key is more complex, such as when you're sorting by name, then resolving collisions
* with integer ID, you'll need to return both. In such a case you would use a wrapper class,
* such as {@code Pair, List