DataSource is queried to load pages of content into a PagedList. A PagedList can grow as
it loads more data, but the data loaded cannot be updated. If the underlying data set is
modified, a new PagedList / DataSource pair must be created to represent the new data.

Loading Pages

To control how and when a PagedList queries data from its DataSource, see
PagedList.Config. The Config object defines things like load sizes and prefetch distance.

Updating Paged Data

A PagedList / DataSource pair are a snapshot of the data set. A new pair of
PagedList / DataSource must be created if an update occurs, such as a reorder, insert, delete, or
content update occurs. A DataSource must detect that it cannot continue loading its
snapshot (for instance, when Database query notices a table being invalidated), and call
invalidate(). Then a new PagedList / DataSource pair would be created to load data from
the new state of the Database query.

To page in data that doesn't update, you can create a single DataSource, and pass it to a single
PagedList. For example, loading from network when the network's paging API doesn't provide
updates.

To page in data from a source that does provide updates, you can create a
DataSource.Factory, where each DataSource created is invalidated when an update to the
data set occurs that makes the current snapshot invalid. For example, when paging a query from
the Database, and the table being queried inserts or removes items. You can also use a
DataSource.Factory to provide multiple versions of network-paged lists. If reloading all content
(e.g. in response to an action like swipe-to-refresh) is required to get a new version of data,
you can connect an explicit refresh signal to call invalidate() on the current
DataSource.

If you have more granular update signals, such as a network API signaling an update to a single
item in the list, it's recommended to load data from network into memory. Then present that
data to the PagedList via a DataSource that wraps an in-memory snapshot. Each time the in-memory
copy changes, invalidate the previous DataSource, and a new one wrapping the new state of the
snapshot can be created.

Implementing a DataSource

Use PageKeyedDataSource if pages you load embed keys for loading adjacent pages. For
example a network response that returns some items, and a next/previous page links.

Use ItemKeyedDataSource if you need to use data from item N-1 to load item
N. For example, if requesting the backend for the next comments in the list
requires the ID or timestamp of the most recent loaded comment, or if querying the next users
from a name-sorted database query requires the name and unique ID of the previous.

Use PositionalDataSource if you can load pages of a requested size at arbitrary
positions, and provide a fixed item count. PositionalDataSource supports querying pages at
arbitrary positions, so can provide data to PagedLists in arbitrary order. Note that
PositionalDataSource is required to respect page size for efficient tiling. If you want to
override page size (e.g. when network page size constraints are only known at runtime), use one
of the other DataSource classes.

Because a null item indicates a placeholder in PagedList, DataSource may not
return null items in lists that it loads. This is so that users of the PagedList
can differentiate unloaded placeholder items from content that has been paged in.