• A String
representing what amounts to a SQL ORDER BY
clause
You are responsible for interpreting these parameters however they make sense and returning a Cursor
that can be used to iterate over and access the data.
As you can imagine, these parameters are aimed toward people using a SQLite database for storage. You are welcome to ignore some of these parameters (e.g., you can elect not to try to roll your own SQL WHERE
-clause parser), but you need to document that fact so activities attempt to query you only by instance Uri and not using parameters you elect not to handle.
For SQLite-backed storage providers, however, the query()
method implementation should be largely boilerplate. Use a SQLiteQueryBuilder
to convert the various parameters into a single SQL statement, then use query()
on the builder to actually invoke the query and give you a Cursor
back. The Cursor
is what your query()
method then returns.
For example, here is query()
from Provider
:
@Override
publicCursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sort) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb. setTables( getTableName());
if( isCollectionUri(url)) {
qb. setProjectionMap( getDefaultProjection());
} else{
qb. appendWhere( getIdColumnName()+"="+url. getPathSegments(). get(1));
}
String orderBy;
if(TextUtils. isEmpty(sort)) {
orderBy = getDefaultSortOrder();
} else{
orderBy = sort;
}
Cursor c = qb. query(db, projection, selection, selectionArgs,
null, null, orderBy);
c. setNotificationUri( getContext(). getContentResolver(), url);
returnc;
}
We create a SQLiteQueryBuilder
and pour the query details into the builder. Note that the query could be based on either a collection or an instance Uri
— in the latter case, we need to add the instance ID to the query. When done, we use the query()
method on the builder to get a Cursor
for the results.
Your insert()
method will receive a Uri
representing the collection and a ContentValues
structure with the initial data for the new instance. You are responsible for creating the new instance, filling in the supplied data, and returning a Uri
to the new instance.
If this is a SQLite-backed content provider, once again, the implementation is mostly boilerplate: validate that all required values were supplied by the activity, merge your own notion of default values with the supplied data, and call insert()
on the database to actually create the instance.
For example, here is insert()
from Provider
:
@Override
publicUri insert(Uri url, ContentValues initialValues) {
long rowID;
ContentValues values;
if(initialValues!= null) {
values = new ContentValues(initialValues);
} else{
values = new ContentValues();
}
if(! isCollectionUri(url)) {
throw new IllegalArgumentException("Unknown URL " + url);
}
for(String colName : getRequiredColumns()) {
if(values. containsKey(colName) == false) {
throw new IllegalArgumentException("Missing column: " + colName);
}
}
populateDefaultValues(values);
rowID = db. insert( getTableName(), getNullColumnHack(), values);
if(rowID > 0) {
Uri uri = ContentUris. withAppendedId( getContentUri(), rowID);
getContext(). getContentResolver(). notifyChange(uri, null);
returnuri;
}
throw new SQLException("Failed to insert row into " + url);
}
The pattern is the same as before: use the provider particulars plus the data to be inserted to actually do the insertion. Please note the following:
• You can insert only into a collection Uri
, so we validate that by calling isCollectionUri()
.
• The provider knows what columns are required ( getRequiredColumns()
), so we iterate over those and confirm our supplied values cover the requirements.
• The provider is responsible for filling in any default values ( populateDefaultValues()
) for columns not supplied in the insert()
call and not automatically handled by the SQLite table definition.
Your update()
method gets the Uri
of the instance or collection to change, a ContentValues
structure with the new values to apply, a String
for a SQL WHERE
clause, and a String[]
with parameters to use to replace ?
found in the WHERE
clause. Your responsibility is to identify the instance(s) to be modified (based on the Uri
and WHERE
clause), then replace those instances’ current property values with the ones supplied.
This will be annoying unless you’re using SQLite for storage. Then you can pretty much pass all the parameters you received to the update()
call to the database, though the update()
call will vary slightly depending on whether you are updating one instance or several.
For example, here is update()
from Provider
:
@Override
publicint update(Uri url, ContentValues values, String where,
String[] whereArgs) {
int count;
if( isCollectionUri(url)) {
count = db. update( getTableName(), values, where, whereArgs);
} else{
String segment = url. getPathSegments(). get(1);
count = db. update( getTableName(), values, getIdColumnName() + "="
+ segment + (!TextUtils. isEmpty(where) ? " AND (" + where + ')' : ""),
whereArgs);
}
getContext(). getContentResolver(). notifyChange(url, null);
Читать дальше