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
public Cursor 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);
return c;
}
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.
insert()
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
public Uri 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);
return uri;
}
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.
update()
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
public int update(Uri url, ContentValues values, String where,
String[] whereArgs) {
int count;
if (isCollectionUri(url)) {
count = db.update(getTableName(), values, where, whereArgs);
} else {