• A Stringrepresenting what amounts to a SQL ORDER BYclause
You are responsible for interpreting these parameters however they make sense and returning a Cursorthat 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 SQLiteQueryBuilderto convert the various parameters into a single SQL statement, then use query()on the builder to actually invoke the query and give you a Cursorback. The Cursoris 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 SQLiteQueryBuilderand 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 Cursorfor the results.
Your insert()method will receive a Urirepresenting the collection and a ContentValuesstructure with the initial data for the new instance. You are responsible for creating the new instance, filling in the supplied data, and returning a Urito 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 Uriof the instance or collection to change, a ContentValuesstructure with the new values to apply, a Stringfor a SQL WHEREclause, and a String[]with parameters to use to replace ?found in the WHEREclause. Your responsibility is to identify the instance(s) to be modified (based on the Uriand WHEREclause), 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);
Читать дальше