Extending the Content Provider class

You define a ContentProvider subclass to expose your data to others using the conventions expected by ContentResolver and Cursor objects. Principally, this means implementing six abstract methods declared in the ContentProvider class:

query()

insert()

update()

delete()

getType()

onCreate()

The query() method must return a Cursor object that can iterate over the requested data. Cursor itself is an interface, but Android provides some ready-made Cursor objects that you can use. For example, SQLiteCursor can iterate over data stored in an SQLite database. You get the Cursor object by calling any of the SQLiteDatabase class's query() methods. There are other Cursor implementations — such as MatrixCursor — for data not stored in a database.

Because these ContentProvider methods can be called from various ContentResolver objects in different processes and threads, they must be implemented in a thread-safe manner.

As a courtesy, you might also want to call ContentResolver.notifvChange() to notify listeners when there are modifications to the data.

Beyond defining the subclass itself, there are other steps you should take to simplify the work of clients and make the class more accessible:

• Define a public static final Un named content_uri. This is the string that represents the full content: URI that your content provider handles. You must define a unique string for this value. The best solution is to use the fully-qualified class name of the content provider (made lowercase). So, for example, the URI for a TransportationProvider class could be defined as follows:

public static final Uri CONTENT_URI =

Uri.parse("content://com.example.codelab.transporationprovider");

If the provider has subtables, also define content_uri constants for each of the subtables. These URIs should all have the same authority (since that identifies the content provider), and be distinguished only by their paths. For example:

content://com.example.codelab.transporationprovider/train content://com.example.codelab.transporationprovider/air/domestic content://com.example.codelab.transporationprovider/air/international

For an overview of content: URIs, see the Content URI Summary at the end of this document.

• Define the column names that the content provider will return to clients. If you are using an underlying database, these column names are typically identical to the SQL database column names they represent. Also define public static String constants that clients can use to specify the columns in queries and other instructions.

Be sure to include an integer column named "_id" (with the constant _id) for the IDs of the records. You should have this field whether or not you have another field (such as a URL) that is also unique among all records. If you're using the SQLite database, the _id field should be the following type:

INTEGER PRIMARY KEY AUTOINCREMENT

The autoincrement descriptor is optional. But without it, SQLite increments an ID counter field to the next number above the largest existing number in the column. If you delete the last row, the next row added will have the same ID as the deleted row. autoincrement avoids this by having SQLite increment to the next largest value whether deleted or not.

• Carefully document the data type of each column. Clients need this information to read the data.

• If you are handling a new data type, you must define a new MIME type to return in your implementation of ContentProvider.aetTvpen. The type depends in part on whether or not the content: URI submitted to getType() limits the request to a specific record. There's one form of the MIME type for a single record and another for multiple records. Use the Un methods to help determine what is being requested. Here is the general format for each type:

° For a single record: vnd.android.cursor.item/vnd.yourcompanyname.contenttype For example, a request for train record 122, like this URI, content://com.example.transportationprovider/trains/12 2 might return this MIME type:

vnd.android.cursor.item/vnd.example.rail o For multiple records: vnd.android.cursor.dir/vnd.yourcompanyname.contenttype For example, a request for all train records, like the following URI, content://com.example.transportationprovider/trains might return this MIME type:

vnd.android.cursor.dir/vnd.example.rail

• If you are exposing byte data that's too big to put in the table itself — such as a large bitmap file — the field that exposes the data to clients should actually contain a content: URI string. This is the field that gives clients access to the data file. The record should also have another field, named "_data" that lists the exact file path on the device for that file. This field is not intended to be read by the client, but by the ContentResolver. The client will call ContentResolver.openInputStream() on the user-facing field holding the URI for the item. The ContentResolver will request the "_data" field for that record, and because it has higher permissions than a client, it should be able to access that file directly and return a read wrapper for the file to the client.

For an example of a private content provider implementation, see the NodePadProvider class in the Notepad sample application that ships with the SDK.

0 0

Post a comment