| page.title=Accessing Content Providers |
| @jd:body |
| |
| <p>If you want to make your data public, you can create (or call) a content |
| provider. This is an object that can store and retrieve data accessible by all |
| applications. This is the only way to share data across packages; there is no |
| common storage area that all packages can share. 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 |
| Android's native content providers in the {@link android.provider provider} package.</p> |
| |
| <p>How a content provider actually stores its data under the covers is up to |
| the implementation of the content provider, but all content providers must |
| implement a common convention to query for data, and a common convention to |
| return results. However, a content provider can implement custom helper |
| functions to make data storage/retrieval simpler for the specific data that it |
| exposes.</p> |
| |
| <p>This document covers two topics related to Content Providers:</p> |
| <ul> |
| <li><a href="#usingacp">Using a Content Provider</a></li> |
| <li><a href="#creatingacontentprovider">Creating a Content Provider</a></li> |
| </ul> |
| |
| <h2>Using a Content Provider to Store and Retrieve Data <a name="usingacp" |
| id="usingacp"></a></h2> |
| |
| <p>This section describes how to store and retrieve data using a content |
| provider implemented by you or anyone else. Android exposes a number of |
| content providers for a wide range of data types, from music and image files |
| to phone numbers. You can see a list of content providers exposed through the |
| convenience classes in the {@link android.provider android.provider} package.</p> |
| |
| <p>Android's content providers are loosely linked to their clients. Each |
| content provider exposes a unique string (a URI) identifying the type of data |
| that it will handle, and the client must use that string to store or retrieve |
| data of that type. We'll explain this more in <a href="#querying">Querying for |
| Data</a>.</p> |
| |
| <p>This section describes the following activities:</p> |
| |
| <ul> |
| <li> |
| <a href="#querying">Querying for Data</a> |
| |
| <ul> |
| <li>Making the query</li> |
| |
| <li>What the query returns</li> |
| |
| <li>Querying for files</li> |
| |
| <li>Reading retrieved data</li> |
| </ul> |
| </li> |
| |
| <li><a href="#modifyingdata">Modifying Data</a></li> |
| |
| <li><a href="#addingrecord">Adding a Record</a></li> |
| |
| <li><a href="#deletingrecord">Deleting a Record</a></li> |
| </ul> |
| |
| <a name="querying" id="querying"></a> |
| <h4>Querying for Data</h4> |
| |
| <p>Each contact provider exposes a unique public URI (wrapped by {@link android.net.Uri}) |
| that is used by a client to query/add/update/delete data on that content |
| provider. This URI has two forms: one to indicate all values of that type |
| (e.g., all personal contacts), and one form to indicate a specific record of |
| that type (e.g., Joe Smith's contact information).</p> |
| |
| <ul> |
| <li><strong>content://contacts/people/</strong> is the URI that would return a list of all contact names on the device.</li> |
| |
| <li><strong>content://contacts/people/23</strong> is the URI string that would return a single result row, the contact with ID = 23. .</li> |
| </ul> |
| |
| <p>An application sends a query to the device that specifies a general type of |
| item (all phone numbers), or a specific item (Bob's phone number), to |
| retrieve. Android then returns a Cursor over a recordset of results, with a |
| specific set of columns. Let's look at a hypothetical query string and a |
| result set (the results have been trimmed a bit for clarity):</p> |
| |
| <p>query = <code>content://contacts/people/</code></p> |
| |
| <p>Results:</p> |
| |
| <table border="1"> |
| <tbody> |
| <tr> |
| <th scope="col">_ID</th> |
| |
| <th scope="col">_COUNT</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>4</td> |
| |
| <td>(425) 555 6677</td> |
| |
| <td>425 555 6677</td> |
| |
| <td>Kirkland office</td> |
| |
| <td>Bully Pulpit</td> |
| |
| <td>Work</td> |
| </tr> |
| |
| <tr> |
| <td>44</td> |
| |
| <td>4</td> |
| |
| <td>(212) 555-1234</td> |
| |
| <td>212 555 1234</td> |
| |
| <td>NY apartment</td> |
| |
| <td>Alan Vain</td> |
| |
| <td>Home</td> |
| </tr> |
| |
| <tr> |
| <td>45</td> |
| |
| <td>4</td> |
| |
| <td>(212) 555-6657</td> |
| |
| <td>212 555 6657</td> |
| |
| <td>Downtown office</td> |
| |
| <td>Alan Vain</td> |
| |
| <td>Work</td> |
| </tr> |
| |
| <tr> |
| <td>53</td> |
| |
| <td>4</td> |
| |
| <td>201.555.4433</td> |
| |
| <td>201 555 4433</td> |
| |
| <td>Love Nest</td> |
| |
| <td>Rex Cars</td> |
| |
| <td>Home</td> |
| </tr> |
| </tbody> |
| </table> |
| |
| <p>Note that the query string isn't a standard SQL query string, but instead a |
| URI string that describes the type of data to return. This URI consists of |
| three parts: the string "content://"; a segment that describes what kind of |
| data to retrieve; and finally an optional ID of a specific item of the |
| specified content type. Here are a few more example query strings:</p> |
| |
| <ul> |
| <li><strong>content://media/internal/images</strong> is the URI string that would return a list of all |
| the internal images on the device.</li> |
| |
| <li><strong>content://media/external/images</strong> is the URI string that would return a list of all |
| the images on the "primary" external storage (e.g., the SD card).</li> |
| |
| <li><strong>content://contacts/people/</strong> is the URI that would return a list of all contact names on the device.</li> |
| |
| <li><strong>content://contacts/people/23</strong> is the URI string that would return a single result row, the contact with ID = 23.</li> |
| </ul> |
| |
| <p>Although there is a general form, these query URIs are somewhat arbitrary and |
| confusing. Therefore, Android provides a list of helper classes in the {@link |
| android.provider} package that |
| define these query strings so you should not need to know the actual URI value |
| for different data types. These helper classes define a string (actually, |
| a {@link android.net.Uri Uri} object) |
| called CONTENT_URI for a specific data type.</p> |
| |
| <p>Typically you will use the defined CONTENT_URI object to make a query, |
| instead of writing the full URI yourself. |
| So, each of the example query strings listed above (except for the last one that specifies the record ID) |
| can be acquired with the following Uri references:</p> |
| |
| <ul> |
| <li>{@link android.provider.MediaStore.Images.Media#INTERNAL_CONTENT_URI |
| MediaStore.Images.Media.INTERNAL_CONTENT_URI}</li> |
| |
| <li>{@link android.provider.MediaStore.Images.Media#EXTERNAL_CONTENT_URI |
| MediaStore.Images.Media.EXTERNAL_CONTENT_URI}</li> |
| |
| <li>{@link android.provider.Contacts.People#CONTENT_URI |
| Contacts.People.CONTENT_URI}</li> |
| </ul> |
| |
| <p>To query a specific record ID (e.g., content://contacts/people/23), |
| you'll use the same CONTENT_URI, but must append the specific ID value that you want. |
| This is one of the few times you should need to examine or modify the URI string. |
| So, for example, if you were looking for record 23 in the people contacts, you might run a query |
| as shown here:</p> |
| <pre> |
| // Get the base URI for contact with _ID=23. |
| // This is same as Uri.parse("content://contacts/people/23"); |
| Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23); |
| // Query for this record. |
| Cursor cur = managedQuery(myPerson, null, null, null); |
| </pre> |
| <p class="note"><strong>Tip:</strong> You can also append a string to a Uri, using |
| {@link android.net.Uri#withAppendedPath(Uri,String)}.</p> |
| |
| <p>This query returns a cursor over a database query result set. What columns |
| are returned, what they're called, and what they are named are discussed next. |
| For now, though, know that you can specify that only certain columns be |
| returned, the sort order, and a SQL WHERE clause.</p> |
| |
| <p>You should use the {@link |
| android.app.Activity#managedQuery(android.net.Uri,java.lang.String[],java.lang.String,java.lang.String[],java.lang.String) Activity.managedQuery()} |
| method to retrieve a managed cursor. A managed cursor handles all the niceties |
| such as unloading itself when the application pauses, and requerying itself |
| when the application restarts. You can ask Android to manage an unmanaged |
| cursor for you by calling {@link |
| android.app.Activity#startManagingCursor(android.database.Cursor) Activity.startManagingCursor()}.</p> |
| |
| <p>Let's look at an example query to retrieve a list of contact names and their primary phone |
| numbers.</p> |
| <pre> |
| // An array specifying which columns to return. |
| string[] projection = new string[] { |
| People._ID, |
| People.NAME, |
| People.NUMBER, |
| }; |
| |
| // Get the base URI for People table in Contacts content provider. |
| // ie. content://contacts/people/ |
| Uri mContacts = People.CONTENT_URI; |
| |
| // Best way to retrieve a query; returns a managed query. |
| Cursor managedCursor = managedQuery( mContacts, |
| projection, //Which columns to return. |
| null, // WHERE clause--we won't specify. |
| People.NAME + " ASC"); // Order-by clause. |
| </pre> |
| |
| <p>This query will retrieve data from the people table of |
| the Contacts content provider. It will retrieve the name, primary phone number, and unique record ID for |
| each contact. </p> |
| |
| <p><strong>What the query returns</strong></p> |
| |
| <p>A query returns a set of zero or more database records. The column names, |
| order, and type are specific to the content provider, but every query includes |
| a column called _id, which is the ID of the item in that row. If a query can |
| return binary data, such as a bitmap or audio file, it will have a column with |
| any name that holds a content:// URI that you can use to get this data (more |
| information on how to get the file will be given later). Here is a tiresome |
| example result set for the previous query:</p> |
| |
| <table border="1"> |
| <tbody> |
| <tr> |
| <th scope="col">_id</th> |
| |
| <th scope="col">name</th> |
| |
| <th scope="col">number</th> |
| |
| |
| </tr> |
| |
| <tr> |
| <td>44</td> |
| |
| <td>Alan Vain</td> |
| |
| <td>212 555 1234</td> |
| |
| |
| </tr> |
| |
| <tr> |
| <td>13</td> |
| |
| <td>Bully Pulpit</td> |
| |
| <td>425 555 6677</td> |
| |
| |
| </tr> |
| |
| <tr> |
| <td>53</td> |
| |
| <td>Rex Cars</td> |
| |
| <td>201 555 4433</td> |
| |
| |
| </tr> |
| </tbody> |
| </table> |
| |
| <p>This result set demonstrates what is returned when we specified a subset of |
| columns to return. The optional subset list is passed in the |
| <em>projection</em> parameter of the query. A content manager should list |
| which columns it supports either by implementing a set of interfaces |
| describing each column (see {@link |
| android.provider.Contacts.People.Phones Contacts.People.Phones}, |
| which extends {@link android.provider.BaseColumns BaseColumns}, {@link |
| android.provider.Contacts.PhonesColumns PhonesColumns}, and {@link |
| android.provider.Contacts.PeopleColumns PeopleColumns}), or by |
| listing the column names as constants. Note that you need to |
| know the data type of a column exposed by a content provider in order to be |
| able to read it; the field reading method is specific to the data type, and a |
| column's data type is not exposed programmatically.</p> |
| |
| <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 cursor to |
| read, modify, or delete rows. Adding new rows requires a different object |
| described later.</p> |
| |
| <p>Note that by convention, every recordset includes a field named _id, which |
| is the ID of a specific record, and a _count field, which is a count of |
| records in the current result set. These field names are defined by {@link |
| android.provider.BaseColumns BaseColumns}.</p> |
| |
| <p><strong>Querying for Files</strong></p> |
| |
| <p>The previous query result demonstrates how a file is returned in a data |
| set. The file field is typically (but not required to be) a string path to the |
| file. However, the caller should never try to read and open the file directly |
| (permissions problems for one thing can make this fail). Instead, you should |
| call {@link |
| android.content.ContentResolver#openInputStream(android.net.Uri) ContentResolver.openInputStream()} |
| / {@link |
| android.content.ContentResolver#openOutputStream(android.net.Uri) |
| ContentResolver.openOutputStream()}, |
| or one of the helper functions from a content provider.</p> |
| |
| <p><strong>Reading Retrieved Data</strong></p> |
| |
| <p>The Cursor object retrieved by the 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. You can |
| read data from specific fields in the record, but you must know the data type |
| of the field, because reading data requires a specialized method for each type |
| of data. (If you call the string reading method on most types of columns, |
| Android will give you the String representation of the data.) The Cursor lets |
| you request the column name from the index, or the index number from the |
| column name.</p> |
| |
| <p>If you are reading binary data, such as an image file, you should call |
| {@link |
| android.content.ContentResolver#openOutputStream(android.net.Uri) ContentResolver.openOutputStream()} |
| on the string content:// URI stored in a column name.</p> |
| |
| <p>The following snippet demonstrates reading the name and phone number from |
| our phone number query:</p> |
| <pre> |
| 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> |
| |
| <h3>Modifying Data<a name="modifyingdata" id="modifyingdata"></a></h3> |
| |
| <p>To batch update a group of records (for example, to change "NY" to "New |
| York" in all contact fields), call the {@link |
| android.content.ContentResolver#update(android.net.Uri,android.content.ContentValues,java.lang.String,java.lang.String[]) ContentResolver.update()} |
| method with the columns and values to change.</p> |
| |
| <h3>Adding a New Record <a name="addingrecord" id="addingrecord"></a></h3> |
| |
| <p>To add a new record, call ContentResolver.insert() with the URI of the type |
| of item to add, and a Map of any values you want to set immediately on the new |
| record. This will return the full URI of the new record, including record |
| number, which you can then use to query and get a Cursor over the new |
| record.</p> |
| |
| <pre> |
| ContentValues values = new ContentValues(); |
| Uri phoneUri = null; |
| Uri emailUri = null; |
| |
| values.put(Contacts.People.NAME, "New Contact"); |
| //1 = the new contact is added to favorites |
| //0 = the new contact is not added to favorites |
| values.put(Contacts.People.STARRED,1); |
| |
| //Add Phone Numbers |
| Uri uri = getContentResolver().insert(Contacts.People.CONTENT_URI, values); |
| |
| //The best way to add Contacts data like Phone, email, IM is to |
| //get the CONTENT_URI of the contact just inserted from People's table, |
| //and use withAppendedPath to construct the new Uri to insert into. |
| phoneUri = Uri.withAppendedPath(uri, Contacts.People.Phones.CONTENT_DIRECTORY); |
| |
| values.clear(); |
| values.put(Contacts.Phones.TYPE, Phones.TYPE_MOBILE); |
| values.put(Contacts.Phones.NUMBER, "1233214567"); |
| getContentResolver().insert(phoneUri, values); |
| |
| //Add Email |
| emailUri = Uri.withAppendedPath(uri, ContactMethods.CONTENT_DIRECTORY); |
| |
| values.clear(); |
| //ContactMethods.KIND is used to distinguish different kinds of |
| //contact data like email, im, etc. |
| values.put(ContactMethods.KIND, Contacts.KIND_EMAIL); |
| values.put(ContactMethods.DATA, "[email protected]"); |
| values.put(ContactMethods.TYPE, ContactMethods.TYPE_HOME); |
| getContentResolver().insert(emailUri, values); |
| |
| </pre> |
| |
| <p>To save a file, you can call ContentResolver().openOutputStream() with the |
| URI as shown in the following snippet: |
| </p> |
| <pre> |
| // Save the name and description in a map. Key is the content provider's |
| // column name, value is the value to save in that record field. |
| ContentValues values = new ContentValues(3); |
| values.put(MediaStore.Images.Media.DISPLAY_NAME, "road_trip_1"); |
| values.put(MediaStore.Images.Media.DESCRIPTION, "Day 1, trip to Los Angeles"); |
| values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); |
| |
| // Add a new record without the bitmap, but with the values. |
| // It returns the URI of the new record. |
| Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); |
| |
| try { |
| // Now get a handle to the file for that record, and save the data into it. |
| // sourceBitmap is a Bitmap object representing the file to save to the database. |
| 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>Deleting a Record <a name="deletingrecord" id="deletingrecord"></a></h3> |
| |
| <p>To delete a single record, call {@link |
| android.content.ContentResolver#delete(android.net.Uri,java.lang.String,java.lang.String[]) ContentResolver.delete()} |
| with the URI of a specific row.</p> |
| |
| <p>To delete multiple rows, call ContentResolver.delete() with the URI of the |
| type of record to delete (for example, |
| android.provider.Contacts.People.CONTENT_URI) and a SQL WHERE clause defining |
| which rows to delete (<em>Warning</em>: be sure to include a valid WHERE |
| clause if deleting a general type using ContentResolver.delete(), or else you |
| risk deleting more records than you intended!).</p> |
| |
| <h2>Creating a Content Provider<a name="creatingacontentprovider" |
| id="creatingacontentprovider"></a> </h2> <p>Here is how to create your own |
| content provider to act as a public source for reading and writing a new data |
| type:</p> |
| <ol> |
| <li>Extend |
| {@link android.content.ContentProvider ContentProvider}.</li> |
| <li>Define a <code>public static final {@link android.net.Uri Uri} </code>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 your |
| content provider (lowercase). So, for example: <br> |
| |
| <code>public static final Uri CONTENT_URI = Uri.parse( |
| "content://com.google.codelab.rssprovider");</code></li> |
| <li>Create your system for storing 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, so long as you follow the calling and return |
| value conventions.</li> |
| <li>Define the column names that you will return to your clients. If you are |
| using an underlying database, these column names are typically identical |
| to the SQL database column names they represent. In any case, you should include |
| an integer column named <code>_id</code> to |
| define a specific record number. If using the SQLite database, this should |
| be type <code>INTEGER |
| PRIMARY KEY AUTOINCREMENT</code>. |
| The <code>AUTOINCREMENT</code> descriptor |
| is optional, but by default, SQLite |
| autoincrements an ID counter field to the next number above the largest |
| existing number in the table. If you delete the last row, the next row added |
| will have the same ID as the deleted row. To avoid this by having SQLite |
| increment to the next largest value whether deleted or not, then assign your |
| ID column the following type: INTEGER PRIMARY KEY AUTOINCREMENT. (<strong>Note</strong> You |
| should have a unique _id field whether or not you have another field (such |
| as a URL) that is also unique among all records.) Android provides the |
| {@link android.database.sqlite.SQLiteOpenHelper SQLiteOpenHelper} |
| |
| class to help you create and manage versions of your database. </li> |
| <li>If you are exposing byte data, such as a bitmap file, the field that stores |
| this data should actually be a string field with a content:// URI for that |
| specific file. This is the field that clients will call to retrieve this |
| data. The content provider for that content type (it can be the same content |
| provider or another content provider — for example, if you're storing a photo |
| you would use the media content provider) should implement a field named |
| _data for that record. The _data field 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 {@link |
| android.content.ContentResolver#openOutputStream(android.net.Uri) ContentResolver.openOutputStream()} on the user-facing field holding the URI |
| for the item (for example, the column named photo might have a value content://media/images/4453). |
| 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 that file to the client. </li> |
| <li>Declare public static |
| Strings that clients can use to specify which columns to return, or to specify |
| field values from the cursor. Carefully document the data type of each |
| field. Remember that file fields, such as audio or bitmap fields, are typically |
| returned as string path values </li> |
| <li>Return a {@link android.database.Cursor Cursor} object over a recordset in |
| reply to a query. This means implementing the query(), update(), insert(), |
| and delete() methods. As a courtesy, you might want to call {@link android.content.ContentResolver#notifyChange(android.net.Uri,android.database.ContentObserver) ContentResolver.notifyChange()} to notify |
| listeners about updated information. </li> |
| |
| <li>Add a <code><provider></code> tag to AndroidManifest.xml, and use its |
| <em>authorities</em> attribute to define the authority part of the content type it should |
| handle. For example, if your content type is content://com.example.autos/auto |
| to request a list of all autos, then <em>authorities</em> would be <code>com.example.autos</code>. |
| Set the <em>multiprocess</em> attribute to true if data does not need to |
| be synchronized between multiple running versions of the content provider. </li> |
| |
| <li>If you are handling a new data type, you must define a new MIME type to return |
| for your implementation of {@link android.content.ContentProvider#getType(android.net.Uri) android.ContentProvider.getType(url)}. This type corresponds to the <code>content://</code> URI |
| submitted to getType(), which will be one of the content types handled by |
| the provider. The MIME type for each content type has two forms: one for |
| a specific record, and one 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: |
| <ul> |
| <li><code>vnd.android.cursor.item/vnd.<em>yourcompanyname.contenttype</em></code> |
| for a single row. For example, a request for train record 122 using |
| <pre>content://com.example.transportationprovider/trains/122</pre> |
| might return the MIME type |
| <code>vnd.android.cursor.item/vnd.example.rail</code> |
| </li> |
| <li><code>vnd.android.cursor.dir/vnd.<em>yourcompanyname.contenttype</em></code> |
| for multiple rows. For example, a request for all train records using |
| <pre>content://com.example.transportationprovider/trains</pre> |
| might return the MIME type |
| <code>vnd.android.cursor.dir/vnd.example.rail</code> |
| </li> |
| </ul> |
| |
| </li> |
| </ol> |
| <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> |
| <p>Here is a recap of the important parts of a content URI:</p> |
| <p><img src="../../images/content_uri.png" alt="Elements of a content URI" height="80" width="528"> </p> |
| <ol type="A"> |
| <li>Standard required prefix. Never modified. </li> |
| <li>Authority part. For third-party applications, this should be a fully-qualified |
| class to ensure uniqueness. This corresponds to the value in |
| the <code><provider></code> element's <em>authorities</em> attribute: |
| <code><provider class="TransportationProvider" |
| authorities="com.example.transportationprovider" |
| /></code> </li> |
| |
| <li>The path that the content provider uses to determine what kind of data is |
| being requested. This can be zero or more segments: if the content provider |
| exposes only one type of data (only trains, for example), this can be absent. |
| If it provides several types, including subtypes, this can be several elements |
| long: e.g., "<code>land/bus</code>, <code>land/train</code>, <code>sea/ship</code>, |
| and <code>sea/submarine</code>" to give four possibilities.</li> |
| <li>A specific record being requested, if any. This is the _id value of a specific |
| record being requested. If all records of a specific type are being requested, |
| omit this and the trailing slash: <code>content://com.example.transportationprovider/trains</code> </li> |
| </ol> |
| |