| page.title=Content Providers |
| @jd:body |
| |
| <div id="qv-wrapper"> |
| <div id="qv"> |
| <h2>Key classes</h2> |
| <ol> |
| <li>{@link android.content.ContentProvider}</li> |
| <li>{@link android.content.ContentResolver}</li> |
| <li>{@link android.database.Cursor}</li> |
| </ol> |
| |
| <h2>In this document</h2> |
| <ol> |
| <li><a href="#basics">Content provider basics</a></li> |
| <li><a href="#querying">Querying a content provider</a></li> |
| <li><a href="#modifying">Modifying data in a provider</a></li> |
| <li><a href="#creating">Creating a content provider</a></li> |
| <li><a href="#urisum">Content URI summary</a></li> |
| </ol> |
| </div> |
| </div> |
| |
| <p> |
| Content providers store and retrieve data and make it accessible to all |
| applications. They're the only way to share data across applications; there's |
| no common storage area that all Android packages can access. |
| </p> |
| |
| <p> |
| Android ships with a number of content providers for common data types |
| (audio, video, images, personal contact information, and so on). You can |
| see some of them listed in the {@link android.provider android.provider} |
| package. You can query these providers for the data they contain (although, |
| for some, you must acquire the proper permission to read the data). |
| </p> |
| |
| <p> |
| If you want to make your own data public, you have two options: You can |
| create your own content provider (a {@link android.content.ContentProvider} |
| subclass) or you can add the data to an existing provider — if there's |
| one that controls the same type of data and you have permission to write to it. |
| </p> |
| |
| <p> |
| This document is an introduction to using content providers. After a |
| brief discussion of the fundamentals, it explores how to query a content |
| provider, how to modify data controlled by a provider, and how to create |
| a content provider of your own. |
| </p> |
| |
| |
| <h2><a name="basics"></a>Content Provider Basics</h2> |
| |
| <p> |
| How a content provider actually stores its data under the covers is |
| up to its designer. But all content providers implement a common interface |
| for querying the provider and returning results — as well as for |
| adding, altering, and deleting data. |
| </p> |
| |
| <p> |
| It's an interface that clients use indirectly, most generally through |
| {@link android.content.ContentResolver} objects. You get a ContentResolver |
| by calling <code>{@link android.content.Context#getContentResolver |
| getContentResolver()}</code> from within the implementation of an Activity |
| or other application component: |
| </p> |
| |
| <pre>ContentResolver cr = getContentResolver();</pre> |
| |
| <p> |
| You can then use the ContentResolver's methods to interact with whatever |
| content providers you're interested in. |
| </p> |
| |
| <p> |
| When a query is initiated, the Android system identifies the content provider |
| that's the target of the query and makes sure that it is up and running. |
| The system instantiates all ContentProvider objects; you never need to do it |
| on your own. In fact, you never deal directly with ContentProvider objects |
| at all. Typically, there's just a single instance of each type of |
| ContentProvider. But it can communicate with multiple ContentResolver objects |
| in different applications and processes. The interaction between processes is |
| handled by the ContentResolver and ContentProvider classes. |
| </p> |
| |
| |
| <h3>The data model</h3> |
| |
| <p> |
| Content providers expose their data as a simple table on a database model, |
| where each row is a record and each column is data of a particular type |
| and meaning. For example, information about people and their phone numbers |
| might be exposed as follows: |
| </p> |
| |
| <table> |
| <tr> |
| <th scope="col">_ID</th> |
| <th scope="col">NUMBER</th> |
| <th scope="col">NUMBER_KEY</th> |
| <th scope="col">LABEL</th> |
| <th scope="col">NAME</th> |
| <th scope="col">TYPE</th> |
| </tr> |
| <tr> |
| <td>13</td> |
| <td>(425) 555 6677</td> |
| <td>425 555 6677</td> |
| <td>Kirkland office</td> |
| <td>Bully Pulpit</td> |
| <td>{@code TYPE_WORK}</td> |
| </tr> |
| <tr> |
| <td>44</td> |
| <td>(212) 555-1234</td> |
| <td>212 555 1234</td> |
| <td>NY apartment</td> |
| <td>Alan Vain</td> |
| <td>{@code TYPE_HOME}</td> |
| </tr> |
| <tr> |
| <td>45</td> |
| <td>(212) 555-6657</td> |
| <td>212 555 6657</td> |
| <td>Downtown office</td> |
| <td>Alan Vain</td> |
| <td>{@code TYPE_MOBILE}</td> |
| </tr> |
| <tr> |
| <td>53</td> |
| <td>201.555.4433</td> |
| <td>201 555 4433</td> |
| <td>Love Nest</td> |
| <td>Rex Cars</td> |
| <td>{@code TYPE_HOME}</td> |
| </tr> |
| </table> |
| |
| <p> |
| Every record includes a numeric {@code _ID} field that uniquely identifies |
| the record within the table. IDs can be used to match records in related |
| tables — for example, to find a person's phone number in one table |
| and pictures of that person in another. |
| </p> |
| |
| <p> |
| A query returns a {@link android.database.Cursor} object that can move from |
| record to record and column to column to read the contents of each field. |
| It has specialized methods for reading each type of data. So, to read a field, |
| you must know what type of data the field contains. (There's more on query |
| results and Cursor objects later.) |
| </p> |
| |
| |
| <h3><a name="uri"></a>URIs</h3> |
| |
| <p> |
| Each content provider exposes a public URI (wrapped as a {@link android.net.Uri} |
| object) that uniquely identifies its data set. A content provider that controls |
| multiple data sets (multiple tables) exposes a separate URI for each one. All |
| URIs for providers begin with the string "{@code content://}". The {@code content:} |
| scheme identifies the data as being controlled by a content provider. |
| </p> |
| |
| <p> |
| If you're defining a content provider, it's a good idea to also define a |
| constant for its URI, to simplify client code and make future updates cleaner. |
| Android defines {@code CONTENT_URI} constants for all the providers that come |
| with the platform. For example, the URI for the table that matches |
| phone numbers to people and the URI for the table that holds pictures of |
| people (both controlled by the Contacts content provider) are: |
| </p> |
| |
| <p> |
| <p style="margin-left: 2em">{@code android.provider.Contacts.Phones.CONTENT_URI} |
| <br/>{@code android.provider.Contacts.Photos.CONTENT_URI} |
| </p> |
| |
| <p> |
| Similarly, the URIs for the table of recent phone calls and the table |
| of calendar entries are: |
| </p> |
| |
| <p> |
| <p style="margin-left: 2em">{@code android.provider.CallLog.Calls.CONTENT_URI} |
| <br/>{@code android.provider.Calendar.CONTENT_URI} |
| </p> |
| |
| <p> |
| The URI constant is used in all interactions with the content provider. |
| Every {@link android.content.ContentResolver} method takes the URI |
| as its first argument. It's what identifies which provider the ContentResolver |
| should talk to and which table of the provider is being targeted. |
| </p> |
| |
| |
| <h2><a name="querying"></a>Querying a Content Provider</h2> |
| |
| <p> |
| You need three pieces of information to query a content provider: |
| </p> |
| |
| <ul> |
| <li>The URI that identifies the provider</li> |
| <li>The names of the data fields you want to receive</li> |
| <li>The data types for those fields</li> |
| </ul> |
| |
| <p> |
| If you're querying a particular record, you also need the ID for that record. |
| </p> |
| |
| |
| <h3>Making the query</h3> |
| |
| <p> |
| To query a content provider, you can use either the |
| <code>{@link android.content.ContentResolver#query ContentResolver.query()}</code> |
| method or the <code>{@link android.app.Activity#managedQuery |
| Activity.managedQuery()}</code> method. |
| Both methods take the same set of arguments, and both return a |
| Cursor object. However, {@code managedQuery()} |
| causes the activity to manage the life cycle of the Cursor. A managed Cursor |
| handles all of the niceties, such as unloading itself when the activity pauses, |
| and requerying itself when the activity restarts. You can ask an Activity to |
| begin managing an unmanaged Cursor object for you by calling |
| <code>{@link android.app.Activity#startManagingCursor |
| Activity.startManagingCursor()}</code>. |
| </p> |
| |
| <p> |
| The first argument to either <code>{@link android.content.ContentResolver#query query()}</code> |
| or <code>{@link android.app.Activity#managedQuery managedQuery()}</code> is the provider URI |
| — the {@code CONTENT_URI} constant that identifies a particular |
| ContentProvider and data set (see <a href="#uri">URIs</a> earlier). |
| </p> |
| |
| <p> |
| To restrict a query to just one record, you can append the {@code _ID} value for |
| that record to the URI — that is, place a string matching the ID as the |
| last segment of the path part of the URI. For example, if the ID is 23, |
| the URI would be: |
| </p> |
| |
| <p style="margin-left: 2em">{@code content://. . . ./23}</p> |
| |
| <p> |
| There are some helper methods, particularly |
| <code>{@link android.content.ContentUris#withAppendedId |
| ContentUris.withAppendedId()}</code> and <code>{@link |
| android.net.Uri#withAppendedPath Uri.withAppendedPath()}</code>, |
| that make it easy to append an ID to a URI. Both are static methods that return |
| a Uri object with the ID added. So, for example, if you were looking for record |
| 23 in the database of people contacts, you might construct a query as follows: |
| </p> |
| |
| <pre> |
| import android.provider.Contacts.People; |
| import android.content.ContentUris; |
| import android.net.Uri; |
| import android.database.Cursor; |
| |
| // Use the ContentUris method to produce the base URI for the contact with _ID == 23. |
| Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23); |
| |
| // Alternatively, use the Uri method to produce the base URI. |
| // It takes a string rather than an integer. |
| Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23"); |
| |
| // Then query for this specific record: |
| Cursor cur = managedQuery(myPerson, null, null, null, null); |
| </pre> |
| |
| <p> |
| The other arguments to the <code>{@link android.content.ContentResolver#query query()}</code> |
| and <code>{@link android.app.Activity#managedQuery managedQuery()}</code> methods delimit |
| the query in more detail. They are: |
| </p> |
| |
| <ul> |
| <li>The names of the data columns that should be returned. A {@code null} |
| value returns all columns. Otherwise, only columns that are listed by name |
| are returned. All the content providers that come with the platform define |
| constants for their columns. For example, the |
| {@link android.provider.Contacts.Phones android.provider.Contacts.Phones} class |
| defines constants for the names of the columns in the phone table illustrated |
| earlier &mdash {@code _ID}, {@code NUMBER}, {@code NUMBER_KEY}, {@code NAME}, |
| and so on.</li> |
| |
| <li><p>A filter detailing which rows to return, formatted as an SQL {@code WHERE} |
| clause (excluding the {@code WHERE} itself). A {@code null} value returns |
| all rows (unless the URI limits the query to a single record).</p></li> |
| |
| <li><p>Selection arguments.</p></li> |
| |
| <li><p>A sorting order for the rows that are returned, formatted as an SQL |
| {@code ORDER BY} clause (excluding the {@code ORDER BY} itself). A {@code null} |
| value returns the records in the default order for the table, which may be |
| unordered.</p></li> |
| </ul> |
| |
| <p> |
| Let's look at an example query to retrieve a list of contact names and their |
| primary phone numbers: |
| </p> |
| |
| <pre> |
| import android.provider.Contacts.People; |
| import android.database.Cursor; |
| |
| // Form an array specifying which columns to return. |
| String[] projection = new String[] { |
| People._ID, |
| People._COUNT, |
| People.NAME, |
| People.NUMBER |
| }; |
| |
| // Get the base URI for the People table in the Contacts content provider. |
| Uri contacts = People.CONTENT_URI; |
| |
| // Make the query. |
| Cursor managedCursor = managedQuery(contacts, |
| projection, // Which columns to return |
| null, // Which rows to return (all rows) |
| null, // Selection arguments (none) |
| // Put the results in ascending order by name |
| People.NAME + " ASC"); |
| </pre> |
| |
| <p> |
| This query retrieves data from the People table of the Contacts content |
| provider. It gets the name, primary phone number, and unique record ID for |
| each contact. It also reports the number of records that are returned as |
| the {@code _COUNT} field of each record. |
| </p> |
| |
| <p> |
| The constants for the names of the columns are defined in various interfaces |
| — {@code _ID} and {@code _COUNT} in |
| {@link android.provider.BaseColumns BaseColumns}, {@code NAME} in {@link android.provider.Contacts.PeopleColumns PeopleColumns}, and {@code NUMBER} |
| in {@link android.provider.Contacts.PhonesColumns PhoneColumns}. The |
| {@link android.provider.Contacts.People Contacts.People} class implements |
| each of these interfaces, which is why the code example above could refer |
| to them using just the class name. |
| </p> |
| |
| |
| <h3>What a query returns</h3> |
| |
| <p> |
| A query returns a set of zero or more database records. The names of the |
| columns, their default order, and their data types are specific to each |
| content provider. |
| But every provider has an {@code _ID} column, which holds a unique numeric |
| ID for each record. Every provider can also report the number |
| of records returned as the {@code _COUNT} column; its value |
| is the same for all rows. |
| </p> |
| |
| <p> |
| Here is an example result set for the query in the previous section: |
| </p> |
| |
| <table border="1"> |
| <tbody> |
| <tr> |
| <th scope="col">_ID</th> |
| <th scope="col">_COUNT</th> |
| <th scope="col">NAME</th> |
| <th scope="col">NUMBER</th> |
| </tr> |
| <tr> |
| <td>44</td> |
| <td>3</td> |
| <td>Alan Vain</td> |
| <td>212 555 1234</td> |
| </tr> |
| <tr> |
| <td>13</td> |
| <td>3</td> |
| <td>Bully Pulpit</td> |
| <td>425 555 6677</td> |
| </tr> |
| <tr> |
| <td>53</td> |
| <td>3</td> |
| <td>Rex Cars</td> |
| <td>201 555 4433</td> |
| </tr> |
| </tbody> |
| </table> |
| |
| <p> |
| The retrieved data is exposed by a {@link android.database.Cursor Cursor} |
| object that can be used to iterate backward or forward through the result |
| set. You can use this object only to read the data. To add, modify, or |
| delete data, you must use a ContentResolver object. |
| </p> |
| |
| |
| <h3>Reading retrieved data</h3> |
| |
| <p> |
| The Cursor object returned by a query provides access to a recordset of |
| results. If you have queried for a specific record by ID, this set will |
| contain only one value. Otherwise, it can contain multiple values. |
| (If there are no matches, it can also be empty.) You |
| can read data from specific fields in the record, but you must know the |
| data type of the field, because the Cursor object has a separate method |
| for reading each type of data — such as <code>{@link |
| android.database.Cursor#getString getString()}</code>, <code>{@link |
| android.database.Cursor#getInt getInt()}</code>, and <code>{@link |
| android.database.Cursor#getFloat getFloat()}</code>. |
| (However, for most types, if you call the method for reading strings, |
| the Cursor object will give you the String representation of the data.) |
| The Cursor lets you request the column name from the index of the column, |
| or the index number from the column name. |
| </p> |
| |
| <p> |
| The following snippet demonstrates reading names and phone numbers from |
| the query illustrated earlier: |
| </p> |
| |
| <pre> |
| import android.provider.Contacts.People; |
| |
| private void getColumnData(Cursor cur){ |
| if (cur.moveToFirst()) { |
| |
| String name; |
| String phoneNumber; |
| int nameColumn = cur.getColumnIndex(People.NAME); |
| int phoneColumn = cur.getColumnIndex(People.NUMBER); |
| String imagePath; |
| |
| do { |
| // Get the field values |
| name = cur.getString(nameColumn); |
| phoneNumber = cur.getString(phoneColumn); |
| |
| // Do something with the values. |
| ... |
| |
| } while (cur.moveToNext()); |
| |
| } |
| } |
| </pre> |
| |
| <p> |
| If a query can return binary data, such as an image or sound, the data |
| may be directly entered in the table or the table entry for that data may be |
| a string specifying a {@code content:} URI that you can use to get the data. |
| In general, smaller amounts of data (say, from 20 to 50K or less) are most often |
| directly entered in the table and can be read by calling |
| <code>{@link android.database.Cursor#getBlob Cursor.getBlob()}</code>. |
| It returns a byte array. |
| </p> |
| |
| <p> |
| If the table entry is a {@code content:} URI, you should never try to open |
| and read the file directly (for one thing, permissions problems can make this |
| fail). Instead, you should call |
| <code>{@link android.content.ContentResolver#openInputStream |
| ContentResolver.openInputStream()}</code> to get an |
| {@link java.io.InputStream} object that you can use to read the data. |
| </p> |
| |
| |
| <h2><a name="modifying"></a>Modifying Data</h2> |
| |
| <p> |
| Data kept by a content provider can be modified by: |
| </p> |
| |
| <ul> |
| <p><li>Adding new records</li> |
| <li>Adding new values to existing records</li> |
| <li>Batch updating existing records</li> |
| <li>Deleting records</li> |
| </ul> |
| |
| <p> |
| All data modification is accomplished using {@link android.content.ContentResolver} |
| methods. Some content providers require a more restrictive permission for writing |
| data than they do for reading it. If you don't have permission to write to a |
| content provider, the ContentResolver methods will fail. |
| </p> |
| |
| |
| <h3>Adding records</h3> |
| |
| <p> |
| To add a new record to a content provider, first set up a map of key-value pairs |
| in a {@link android.content.ContentValues} object, where each key matches |
| the name of a column in the content provider and the value is the desired |
| value for the new record in that column. Then call <code>{@link |
| android.content.ContentResolver#insert ContentResolver.insert()}</code> and pass |
| it the URI of the provider and the ContentValues map. This method returns |
| the full URI of the new record — that is, the provider's URI with |
| the appended ID for the new record. You can then use this URI to query and |
| get a Cursor over the new record, and to further modify the record. |
| Here's an example: |
| </p> |
| |
| <pre> |
| import android.provider.Contacts.People; |
| import android.content.ContentResolver; |
| import android.content.ContentValues; |
| |
| ContentValues values = new ContentValues(); |
| |
| // Add Abraham Lincoln to contacts and make him a favorite. |
| values.put(People.NAME, "Abraham Lincoln"); |
| // 1 = the new contact is added to favorites |
| // 0 = the new contact is not added to favorites |
| values.put(People.STARRED, 1); |
| |
| Uri uri = getContentResolver().insert(People.CONTENT_URI, values); |
| </pre> |
| |
| |
| <h3>Adding new values</h3> |
| |
| <p> |
| Once a record exists, you can add new information to it or modify |
| existing information. For example, the next step in the example above would |
| be to add contact information — like a phone number or an IM or e-mail |
| address — to the new entry. |
| </p> |
| |
| <p> |
| The best way to add to a record in the Contacts database is to append |
| the name of the table where the new data goes to the URI for the |
| record, then use the amended URI to add the new data values. Each |
| Contacts table exposes a name for this purpose as a {@code |
| CONTENT_DIRECTORY} constant. The following code continues the previous |
| example by adding a phone number and e-mail address for the record |
| just created: |
| </p> |
| |
| <pre> |
| Uri phoneUri = null; |
| Uri emailUri = null; |
| |
| // Add a phone number for Abraham Lincoln. Begin with the URI for |
| // the new record just returned by insert(); it ends with the _ID |
| // of the new record, so we don't have to add the ID ourselves. |
| // Then append the designation for the phone table to this URI, |
| // and use the resulting URI to insert the phone number. |
| phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY); |
| |
| values.clear(); |
| values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE); |
| values.put(People.Phones.NUMBER, "1233214567"); |
| getContentResolver().insert(phoneUri, values); |
| |
| // Now add an email address in the same way. |
| emailUri = Uri.withAppendedPath(uri, People.ContactMethods.CONTENT_DIRECTORY); |
| |
| values.clear(); |
| // ContactMethods.KIND is used to distinguish different kinds of |
| // contact methods, such as email, IM, etc. |
| values.put(People.ContactMethods.KIND, Contacts.KIND_EMAIL); |
| values.put(People.ContactMethods.DATA, "test@example.com"); |
| values.put(People.ContactMethods.TYPE, People.ContactMethods.TYPE_HOME); |
| getContentResolver().insert(emailUri, values); |
| </pre> |
| |
| <p> |
| You can place small amounts of binary data into a table by calling |
| the version of <code>{@link android.content.ContentValues#put |
| ContentValues.put()}</code> that takes a byte array. |
| That would work for a small icon-like image or a short audio clip, for example. |
| However, if you have a large amount of binary data to add, such as a photograph |
| or a complete song, put a {@code content:} URI for the data in the table and call |
| <code>{@link android.content.ContentResolver#openOutputStream |
| ContentResolver.openOutputStream()}</code> |
| with the file's URI. (That causes the content provider to store the data |
| in a file and record the file path in a hidden field of the record.) |
| </p> |
| |
| <p> |
| In this regard, the {@link android.provider.MediaStore} content |
| provider, the main provider that dispenses image, audio, and video |
| data, employs a special convention: The same URI that is used with |
| {@code query()} or {@code managedQuery()} to get meta-information |
| about the binary data (such as, the caption of a photograph or the |
| date it was taken) is used with {@code openInputStream()} |
| to get the data itself. Similarly, the same URI that is used with |
| {@code insert()} to put meta-information into a MediaStore record |
| is used with {@code openOutputStream()} to place the binary data there. |
| The following code snippet illustrates this convention: |
| </p> |
| |
| <pre> |
| import android.provider.MediaStore.Images.Media; |
| import android.content.ContentValues; |
| import java.io.OutputStream; |
| |
| // Save the name and description of an image in a ContentValues map. |
| ContentValues values = new ContentValues(3); |
| values.put(Media.DISPLAY_NAME, "road_trip_1"); |
| values.put(Media.DESCRIPTION, "Day 1, trip to Los Angeles"); |
| values.put(Media.MIME_TYPE, "image/jpeg"); |
| |
| // Add a new record without the bitmap, but with the values just set. |
| // insert() returns the URI of the new record. |
| Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values); |
| |
| // Now get a handle to the file for that record, and save the data into it. |
| // Here, sourceBitmap is a Bitmap object representing the file to save to the database. |
| try { |
| OutputStream outStream = getContentResolver().openOutputStream(uri); |
| sourceBitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream); |
| outStream.close(); |
| } catch (Exception e) { |
| Log.e(TAG, "exception while writing image", e); |
| } |
| </pre> |
| |
| |
| <h3>Batch updating records</h3> |
| |
| <p> |
| To batch update a group of records (for example, to change "NY" to "New York" |
| in all fields), call the <code>{@link |
| android.content.ContentResolver#update ContentResolver.update()}</code> |
| method with the columns and values to change. |
| </p> |
| |
| |
| <h3><a name="deletingrecord"></a>Deleting a record</h3> |
| |
| <p> |
| To delete a single record, call {<code>{@link |
| android.content.ContentResolver#delete ContentResolver.delete()}</code> |
| with the URI of a specific row. |
| </p> |
| |
| <p> |
| To delete multiple rows, call <code>{@link |
| android.content.ContentResolver#delete ContentResolver.delete()}</code> |
| with the URI of the type of record to delete (for example, {@code android.provider.Contacts.People.CONTENT_URI}) and an SQL {@code WHERE} |
| clause defining which rows to delete. (<i><b>Caution</b>: |
| Be sure to include a valid {@code WHERE} clause if you're deleting a general |
| type, or you risk deleting more records than you intended!</i>). |
| </p> |
| |
| |
| <h2><a name="creating"></a>Creating a Content Provider</h2> |
| |
| <p> |
| To create a content provider, you must: |
| </p> |
| |
| <ul> |
| <li>Set up a system for storing the data. Most content providers |
| store their data using Android's file storage methods or SQLite databases, |
| but you can store your data any way you want. Android provides the |
| {@link android.database.sqlite.SQLiteOpenHelper SQLiteOpenHelper} |
| class to help you create a database and {@link |
| android.database.sqlite.SQLiteDatabase SQLiteDatabase} to manage it.</li> |
| |
| <li><p>Extend the {@link android.content.ContentProvider} class to provide |
| access to the data.</p></li> |
| |
| <li><p>Declare the content provider in the manifest file for your |
| application (AndroidManifest.xml).</p></li> |
| </ul> |
| |
| <p> |
| The following sections have notes on the last two of these tasks. |
| </p> |
| |
| |
| <h3>Extending the ContentProvider class</h3> |
| |
| <p> |
| You define a {@link android.content.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: |
| </p> |
| |
| <p style="margin-left: 2em">{@code query()} |
| <br/>{@code insert()} |
| <br/>{@code update()} |
| <br/>{@code delete()} |
| <br/>{@code getType()} |
| <br/>{@code onCreate()}</p> |
| |
| <p> |
| The {@code query()} method must return a {@link android.database.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, |
| {@link android.database.sqlite.SQLiteCursor} can iterate over data stored in |
| an SQLite database. You get the Cursor object by calling any of the {@link |
| android.database.sqlite.SQLiteDatabase SQLiteDatabase} class's {@code query()} |
| methods. There are other Cursor implementations — such as {@link |
| android.database.MatrixCursor} — for data not stored in a database. |
| </p> |
| |
| <p> |
| 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. |
| </p> |
| |
| <p> |
| As a courtesy, you might also want to call <code>{@link android.content.ContentResolver#notifyChange(android.net.Uri,android.database.ContentObserver) |
| ContentResolver.notifyChange()}</code> to notify listeners when there are |
| modifications to the data. |
| </p> |
| |
| <p> |
| Beyond defining the subclass itself, there are other steps you should take |
| to simplify the work of clients and make the class more accessible: |
| </p> |
| |
| <ul> |
| <li>Define a {@code public static final} {@link android.net.Uri} |
| named {@code CONTENT_URI}. This is the string that represents the full |
| {@code 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: |
| |
| <pre>public static final Uri CONTENT_URI = |
| Uri.parse("content://com.example.codelab.transportationprovider");</pre> |
| |
| <p> |
| If the provider has subtables, also define {@code 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: |
| </p> |
| |
| <p style="margin-left: 2em">{@code content://com.example.codelab.transportationprovider/train} |
| <br/>{@code content://com.example.codelab.transportationprovider/air/domestic} |
| <br/>{@code content://com.example.codelab.transportationprovider/air/international}</p> |
| |
| <p> |
| For an overview of {@code content:} URIs, see the <a href="#urisum">Content URI |
| Summary</a> at the end of this document. |
| </p></li> |
| |
| <li><p>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 |
| {@code public static} String constants that clients can use to specify |
| the columns in queries and other instructions. |
| </p> |
| |
| <p> |
| Be sure to include an integer column named "{@code _id}" |
| (with the constant {@code _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 {@code _ID} field should be the |
| following type: |
| </p> |
| |
| <p style="margin-left: 2em">{@code INTEGER PRIMARY KEY AUTOINCREMENT}</p> |
| |
| <p> |
| The {@code 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. {@code AUTOINCREMENT} avoids this |
| by having SQLite increment to the next largest value whether deleted or not. |
| </p> |
| </li> |
| |
| <li><p>Carefully document the data type of each column. Clients need this |
| information to read the data.</p></li> |
| |
| <li><p>If you are handling a new data type, you must define a new MIME type |
| to return in your implementation of <code>{@link |
| android.content.ContentProvider#getType ContentProvider.getType()}</code>. |
| The type depends in part on whether or not the {@code content:} URI submitted |
| to {@code 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 {@link android.net.Uri Uri} methods to help determine what is being |
| requested. Here is the general format for each type:</p></li> |
| |
| <ul> |
| <li><p>For a single record: {@code vnd.android.cursor.item/vnd.<em>yourcompanyname.contenttype</em}</p> |
| |
| <p>For example, a request for train record 122, like this URI,</p> |
| <p style="margin-left: 2em">{@code content://com.example.transportationprovider/trains/122}</p> |
| |
| <p>might return this MIME type:</p> |
| <p style="margin-left: 2em">{@code vnd.android.cursor.item/vnd.example.rail}</p> |
| </li> |
| |
| <li><p>For multiple records: {@code vnd.android.cursor.dir/vnd.<em>yourcompanyname.contenttype</em>}</p> |
| |
| <p>For example, a request for all train records, like the following URI,</p> |
| <p style="margin-left: 2em">{@code content://com.example.transportationprovider/trains}</p> |
| |
| <p>might return this MIME type:</p> |
| <p style="margin-left: 2em">{@code vnd.android.cursor.dir/vnd.example.rail}</p> |
| </li> |
| </ul> |
| |
| <li><p>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 {@code content:} URI string. |
| This is the field that gives clients access to the data file. The record |
| should also have another field, named "{@code _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 <code>{@link |
| android.content.ContentResolver#openInputStream ContentResolver.openInputStream()}</code> |
| on the user-facing field holding the URI for the item. The ContentResolver |
| will request the "{@code _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.</p></li> |
| |
| </ul> |
| |
| <p> |
| For an example of a private content provider implementation, see the |
| NodePadProvider class in the Notepad sample application that ships with the SDK. |
| </p> |
| |
| |
| <h3>Declaring the content provider</h3> |
| |
| <p> |
| To let the Android system know about the content provider you've developed, |
| declare it with a {@code <provider>} element in the application's |
| AndroidManifest.xml file. Content providers that are not declared in the |
| manifest are not visible to the Android system |
| </p> |
| |
| <p> |
| The {@code name} attribute is the fully qualified name of the ContentProvider |
| subclass. The {@code authorities} attribute is the authority part of the |
| {@code content:} URI that identifies the provider. |
| For example if the ContentProvider subclass is AutoInfoProvider, the |
| {@code <provider>} element might look like this: |
| </p> |
| |
| <pre> |
| <provider name="com.example.autos.AutoInfoProvider" |
| authorities="com.example.autos.autoinfoprovider" |
| . . . /> |
| </provider> |
| </pre> |
| |
| <p> |
| Note that the {@code authorities} attribute omits the path part of a |
| {@code content:} URI. For example, if AutoInfoProvider controlled subtables |
| for different types of autos or different manufacturers, |
| </p> |
| |
| <p style="margin-left: 2em">{@code content://com.example.autos.autoinfoprovider/honda} |
| <br/>{@code content://com.example.autos.autoinfoprovider/gm/compact} |
| <br/>{@code content://com.example.autos.autoinfoprovider/gm/suv}</p> |
| |
| <p> |
| those paths would not be declared in the manifest. The authority is what |
| identifies the provider, not the path; your provider can interpret the path |
| part of the URI in any way you choose. |
| </p> |
| |
| <p> |
| Other {@code <provider>} attributes can set permissions to read and |
| write data, provide for an icon and text that can be displayed to users, |
| enable and disable the provider, and so on. Set the {@code multiprocess} |
| attribute to "{@code true}" if data does not need to be synchronized between |
| multiple running versions of the content provider. This permits an instance |
| of the provider to be created in each client process, eliminating the need |
| to perform IPC. |
| </p> |
| |
| |
| <h2><a name="urisum"></a>Content URI Summary</h2> |
| |
| <p> |
| Here is a recap of the important parts of a content URI: |
| </p> |
| |
| <p> |
| <img src="{@docRoot}images/content_uri.png" alt="Elements of a content URI" |
| height="80" width="528"> |
| </p> |
| |
| <ol type="A"> |
| <li>Standard prefix indicating that the data is controlled by a |
| content provider. It's never modified.</li> |
| |
| <li><p>The authority part of the URI; it identifies the content provider. |
| For third-party applications, this should be a fully-qualified class name |
| (reduced to lowercase) to ensure uniqueness. The authority is declared in |
| the {@code <provider>} element's {@code authorities} attribute:</p> |
| |
| <pre><provider name=".TransportationProvider" |
| authorities="com.example.transportationprovider" |
| . . . ></pre></li> |
| |
| <li><p>The path that the content provider uses to determine what kind of data is |
| being requested. This can be zero or more segments long. If the content provider |
| exposes only one type of data (only trains, for example), it can be absent. |
| If the provider exposes several types, including subtypes, it can be several |
| segments long — for example, "{@code land/bus}", "{@code land/train}", |
| "{@code sea/ship}", and "{@code sea/submarine}" to give four possibilities.</p></li> |
| |
| <li><p>The ID of the specific record being requested, if any. This is the |
| {@code _ID} value of the requested record. If the request is not limited to |
| a single record, this segment and the trailing slash are omitted:</p> |
| |
| <p style="margin-left: 2em">{@code content://com.example.transportationprovider/trains}</p> |
| </li> |
| </ol> |
| |
| |