* commit '9f426604e6f21e31f8a2194dcff0ea7bf488eee2': DOC CHANGE: New Content Provider topics
This commit is contained in:
@ -87,8 +87,22 @@
|
||||
<span class="en">Content Providers</span>
|
||||
</a></div>
|
||||
<ul>
|
||||
<li><a href="<?cs var:toroot ?>guide/topics/providers/calendar-provider.html">
|
||||
<span class="en">Calendar Provider</span></a>
|
||||
<li>
|
||||
<a href="<?cs var:toroot ?>guide/topics/providers/content-provider-basics.html">
|
||||
<span class="en">Content Provider Basics</span>
|
||||
</a>
|
||||
<span class="new">new!</span>
|
||||
</li>
|
||||
<li>
|
||||
<a href="<?cs var:toroot ?>guide/topics/providers/content-provider-creating.html">
|
||||
<span class="en">Creating a Content Provider</span>
|
||||
</a>
|
||||
<span class="new">new!</span>
|
||||
</li>
|
||||
<li>
|
||||
<a href="<?cs var:toroot ?>guide/topics/providers/calendar-provider.html">
|
||||
<span class="en">Calendar Provider</span>
|
||||
</a>
|
||||
<span class="new">new!</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
1215
docs/html/guide/topics/providers/content-provider-basics.jd
Normal file
1215
docs/html/guide/topics/providers/content-provider-basics.jd
Normal file
File diff suppressed because it is too large
Load Diff
1215
docs/html/guide/topics/providers/content-provider-creating.jd
Normal file
1215
docs/html/guide/topics/providers/content-provider-creating.jd
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,922 +1,96 @@
|
||||
page.title=Content Providers
|
||||
@jd:body
|
||||
|
||||
<div id="qv-wrapper">
|
||||
<div id="qv">
|
||||
|
||||
<h2>In this document</h2>
|
||||
|
||||
<!-- In this document -->
|
||||
<h2>Topics</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>
|
||||
<li>
|
||||
<a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
|
||||
Content Provider Basics</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
|
||||
Creating a Content Provider</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar Provider</a>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<h2>Key classes</h2>
|
||||
<!-- Related Samples -->
|
||||
<h2>Related Samples</h2>
|
||||
<ol>
|
||||
<li>{@link android.content.ContentProvider}</li>
|
||||
<li>{@link android.content.ContentResolver}</li>
|
||||
<li>{@link android.database.Cursor}</li>
|
||||
</ol>
|
||||
|
||||
<h2>See also</h2>
|
||||
<ol>
|
||||
<li><a href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar Provider</a></li>
|
||||
<li>
|
||||
<a href="{@docRoot}resources/samples/ContactManager/index.html">
|
||||
Contact Manager</a> application
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html">
|
||||
"Cursor (People)"
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html">
|
||||
"Cursor (Phones)"</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.
|
||||
Content providers manage access to a structured set of data. They encapsulate the
|
||||
data, and provide mechanisms for defining data security. Content providers are the standard
|
||||
interface that connects data in one process with code running in another process.
|
||||
</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).
|
||||
When you want to access data in a content provider, you use the
|
||||
{@link android.content.ContentResolver} object in your
|
||||
application's {@link android.content.Context} to communicate with the provider as a client.
|
||||
The {@link android.content.ContentResolver} object communicates with the provider object, an
|
||||
instance of a class that implements {@link android.content.ContentProvider}. The provider
|
||||
object receives data requests from clients, performs the requested action, and
|
||||
returns the results.
|
||||
</p>
|
||||
|
||||
<p class="note"><strong>Note:</strong> Android 4.0 introduces the Calendar
|
||||
Provider. For more information, see <a
|
||||
href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar
|
||||
Provider</a>.</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.
|
||||
You don't need to develop your own provider if you don't intend to share your data with
|
||||
other applications. However, you do need your own provider to provide custom search
|
||||
suggestions in your own application. You also need your own provider if you want to copy and
|
||||
paste complex data or files from your application to other applications.
|
||||
</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.
|
||||
Android itself includes content providers that manage data such as audio, video, images, and
|
||||
personal contact information. You can see some of them listed in the reference
|
||||
documentation for the
|
||||
<code><a href="{@docRoot}reference/android/provider/package-summary.html">android.provider</a>
|
||||
</code> package. With some restrictions, these providers are accessible to any Android
|
||||
application.
|
||||
</p><p>
|
||||
The following topics describe content providers in more detail:
|
||||
</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>
|
||||
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 — {@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 android:name="com.example.autos.AutoInfoProvider"
|
||||
android: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 android:name=".TransportationProvider"
|
||||
android: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>
|
||||
|
||||
|
||||
<dl>
|
||||
<dt>
|
||||
<strong><a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
|
||||
Content Provider Basics</a></strong>
|
||||
</dt>
|
||||
<dd>
|
||||
How to access data in a content provider when the data is organized in tables.
|
||||
</dd>
|
||||
<dt>
|
||||
<strong><a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
|
||||
Creating a Content Provider</a></strong>
|
||||
</dt>
|
||||
<dd>
|
||||
How to create your own content provider.
|
||||
</dd>
|
||||
<dt>
|
||||
<strong><a href="{@docRoot}guide/topics/providers/calendar-provider.html">
|
||||
Calendar Provider</a></strong>
|
||||
</dt>
|
||||
<dd>
|
||||
How to access the Calendar Provider that is part of the Android platform.
|
||||
</dd>
|
||||
</dl>
|
||||
|
Reference in New Issue
Block a user