Of course, content providers would be astonishingly weak if you couldn’t add or remove data from them, only update what is there. Fortunately, content providers offer these abilities as well.
To insert data into a content provider, you have two options available on the ContentProvider
interface (available through getContentProvider()
to your activity):
• Use insert()
with a collection Uri
and a ContentValues
structure describing the initial set of data to put in the row
• Use bulkInsert()
with a collection Uri
and an array of ContentValues
structures to populate several rows at once
The insert()
method returns a Uri
for you to use for future operations on that new object. The bulkInsert()
method returns the number of created rows; you would need to do a query to get back at the data you just inserted.
For example, here is a snippet of code from ConstantsBrowser
to insert a new constant into the content provider, given a DialogWrapper
that can provide access to the title and value of the constant:
private void processAdd(DialogWrapper wrapper) {
ContentValues values = new ContentValues(2);
values.put(Provider.Constants.TITLE, wrapper.getTitle ());
values.put(Provider.Constants.VALUE, wrapper.getValue ());
getContentResolver().insert (Provider.Constants.CONTENT_URI,
values);
constantsCursor.requery();
}
Since we already have an outstanding Cursor
for the content provider’s contents, we call requery()
on that to update the Cursor
’s contents. This, in turn, will update any SimpleCursorAdapter
you may have wrapping the Cursor
— and that will update any selection widgets (e.g., ListView
) you have using the adapter.
To delete one or more rows from the content provider, use the delete()
method on ContentResolver
. This works akin to a SQL DELETE
statement and takes three parameters:
1. A Uri
representing the collection (or instance) you wish to update
2. A constraint statement, functioning like a SQL WHERE
clause, to determine which rows should be updated
3. An optional set of parameters to bind into the constraint clause, replacing any ?s that appear there
Beware of the BLOB!
Binary large objects — BLOBs — are supported in many databases, including SQLite. However, the Android model is more aimed at supporting such hunks of data via their own separate content Uri
values. A content provider, therefore, does not provide direct access to binary data, like photos, via a Cursor
. Rather, a property in the content provider will give you the content Uri
for that particular BLOB. You can use getInputStream()
and getOutputStream()
on your ContentProvider
to read and write the binary data.
Quite possibly, the rationale is to minimize unnecessary data copying. For example, the primary use of a photo in Android is to display it to the user. The ImageView
widget can do just that, via a content Uri
to a JPEG. By storing the photo in a manner that has its own Uri
, you do not need to copy data out of the content provider into some temporary holding area just to be able to display it — just use the Uri
. The expectation, presumably, is that few Android applications will do much more than upload binary data and use widgets or built-in activities to display that data.
CHAPTER 28
Building a Content Provider
Building a content provider is probably the most complicated and tedious task in all of Android development. There are many requirements of a content provider, in terms of methods to implement and public data members to supply. And, until you try using it, you have no great way of telling if you did any of it correctly (versus, say, building an activity and getting validation errors from the resource compiler).
That being said, building a content provider is of huge importance if your application wishes to make data available to other applications. If your application is keeping its data solely to itself, you may be able to avoid creating a content provider, just accessing the data directly from your activities. But if you want your data to possibly be used by others — for example, if you are building a feed reader and you want other programs to be able to access the feeds you are downloading and caching — then a content provider is right for you.
First, Some Dissection
As was discussed in the previous chapter, the content Uri
is the linchpin behind accessing data inside a content provider. When using a content provider, all you really need to know is the provider’s base Uri
; from there you can run queries as needed or construct a Uri
to a specific instance if you know the instance identifier.
When building a content provider, though, you need to know a bit more about the innards of the content Uri
.
A content Uri
has two to four pieces, depending on the situation:
• It always has a scheme (content://
), indicating it is a content Uri
instead of a Uri
to a Web resource (http://
).
• It always has an authority, which is the first path segment after the scheme. The authority is a unique string identifying the content provider that handles the content associated with this Uri
.
• It may have a data type path, which is the list of path segments after the authority and before the instance identifier (if any). The data type path can be empty if the content provider handles only one type of content. It can be a single path segment (foo
) or a chain of path segments (foo/bar/goo
) as needed to handle whatever data-access scenarios the content provider requires.
• It may have an instance identifier, which is an integer identifying a specific piece of content. A content Uri
without an instance identifier refers to the collection of content represented by the authority