belongs to Maven artifact com.android.support:support-content:28.0.0-alpha1
ContentPager
public
class
ContentPager
extends Object
java.lang.Object | |
↳ | android.support.content.ContentPager |
ContentPager
provides support for loading "paged" data on a background thread
using the ContentResolver
framework. This provides an effective compatibility
layer for the ContentResolver "paging" support added in Android O. Those Android O changes,
like this class, help reduce or eliminate the occurrence of expensive inter-process
shared memory operations (aka "CursorWindow swaps") happening on the UI thread when
working with remote providers.
The list of terms used in this document:
- "The provider" is a
- If the system is Android O and greater and the provider supports paging, the Cursor
will be returned, effectively unmodified, to a
ContentPager.ContentCallback
supplied by your application. - If the system is less than Android O or the provider does not support paging, the
loader will fetch an unpaged Cursor from the provider. The unpaged Cursor will be held
by the ContentPager, and data will be copied into a new cursor in a background thread.
The new cursor will be returned to a
ContentPager.ContentCallback
supplied by your application.In either cases, when an application employs this library it can generally assume that there will be no CursorWindow swap. But picking the right limit for records can help reduce or even eliminate some heavy lifting done to guard against swaps.
How do we avoid that entirely?
Picking a reasonable item limit
Authors are encouraged to experiment with limits using real data and the widest column projection they'll use in their app. The total number of records that will fit into shared memory varies depending on multiple factors.
- The number of columns being requested in the cursor projection. Limit the number of columns, to reduce the size of each row.
- The size of the data in each column.
- the Cursor type.
If the cursor is running in-process, there may be no need for paging. Depending on the Cursor implementation chosen there may be no shared memory/CursorWindow in use. NOTE: If the provider is running in your process, you should implement paging support inorder to make your app run fast and to consume the fewest resources possible.
In common cases where there is a low volume (in the hundreds) of records in the dataset being queried, all of the data should easily fit in shared memory. A debugger can be handy to understand with greater accuracy how many results can fit in shared memory. Inspect the Cursor object returned from a call to
query(Uri, String[], String, String[], String)
. If the underlying type is aCrossProcessCursor
orAbstractWindowedCursor
it'll have aCursorWindow
field. CheckgetNumRows()
. If getNumRows returns less thangetCount()
, then you've found something close to the max rows that'll fit in a page. If the data in row is expected to be relatively stable in size, reduce row count by 15-20% to get a reasonable max page size.What if the limit I guessed was wrong?
The library includes safeguards that protect against situations where an author specifies a record limit that exceeds the number of rows accessible without a CursorWindow swap. In such a circumstance, the Cursor will be adapted to report a count ({Cursor#getCount}) that reflects only records available without CursorWindow swap. But this involves extra work that can be eliminated with a correct limit.
In addition to adjusted coujnt,
EXTRA_SUGGESTED_LIMIT
will be included in cursor extras. When EXTRA_SUGGESTED_LIMIT is present in extras, the client should strongly consider using this value as the limit for subsequent queries as doing so should help avoid the ned to wrap pre-paged cursors.Lifecycle and cleanup
Cursors resulting from queries are owned by the requesting client. So they must be closed by the client at the appropriate time.
However, the library retains an internal cache of content that needs to be cleaned up. In order to cleanup, call
reset()
.Projections
Note that projection is ignored when determining the identity of a query. When adding or removing projection, clients should call
reset()
to clear cached data.Summary
Nested classes
interface
ContentPager.ContentCallback
Callback by which a client receives results of a query.
@interface
ContentPager.CursorDisposition
interface
ContentPager.QueryRunner
Implementations of this interface provide the mechanism for execution of queries off the UI thread.
Constants
int
CURSOR_DISPOSITION_COPIED
The cursor size exceeded page size.
int
CURSOR_DISPOSITION_PAGED
The cursor was provider paged.
int
CURSOR_DISPOSITION_REPAGED
The cursor was pre-paged, but total size was larger than CursorWindow size.
int
CURSOR_DISPOSITION_WRAPPED
The cursor was not pre-paged, but total size was smaller than page size.
String
EXTRA_HONORED_ARGS
String
EXTRA_REQUESTED_LIMIT
Denotes the requested limit, if the limit was not-honored.
String
EXTRA_SUGGESTED_LIMIT
Specifies a limit likely to fit in CursorWindow limit.
String
EXTRA_TOTAL_COUNT
String
QUERY_ARG_LIMIT
String
QUERY_ARG_OFFSET
Public constructors
ContentProvider
supplying data identified
by a specific content Uri
. A provider is the source of data, and for the sake of
this documents, the provider resides in a remote process.
- "supports paging" A provider supports paging when it returns a pre-paged
Cursor
that honors the paging contract. See @link ContentResolver#QUERY_ARG_OFFSET} and
QUERY_ARG_LIMIT
for details on the contract.
- "CursorWindow swaps" The process by which new data is loaded into a shared memory
via a CursorWindow instance. This is a prominent contributor to UI jank in applications
that use Cursor as backing data for UI elements like
RecyclerView
.
Details
Data will be loaded from a content uri in one of two ways, depending on the runtime environment and if the provider supports paging.