diff options
-rw-r--r-- | docs/html/guide/guide_toc.cs | 22 | ||||
-rw-r--r-- | docs/html/guide/topics/providers/content-provider-basics.jd | 1215 | ||||
-rw-r--r-- | docs/html/guide/topics/providers/content-provider-creating.jd | 1215 | ||||
-rw-r--r-- | docs/html/guide/topics/providers/content-providers.jd | 994 |
4 files changed, 2532 insertions, 914 deletions
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index ee4c48e..4e5badd 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -87,10 +87,24 @@ <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> - <span class="new">new!</span> - </li> + <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> </li> <li><a href="<?cs var:toroot ?>guide/topics/intents/intents-filters.html"> diff --git a/docs/html/guide/topics/providers/content-provider-basics.jd b/docs/html/guide/topics/providers/content-provider-basics.jd new file mode 100644 index 0000000..40b5c3f --- /dev/null +++ b/docs/html/guide/topics/providers/content-provider-basics.jd @@ -0,0 +1,1215 @@ +page.title=Content Provider Basics +@jd:body +<div id="qv-wrapper"> +<div id="qv"> + + + <!-- In this document --> +<h2>In this document</h2> +<ol> + <li> + <a href="#Basics">Overview</a> + <ol> + <li> + <a href="#ClientProvider">Accessing a provider</a> + </li> + <li> + <a href="#ContentURIs">Content URIs</a> + </li> + </ol> + </li> + <li> + <a href="#SimpleQuery">Retrieving Data from the Provider</a> + <ol> + <li> + <a href="#RequestPermissions">Requesting read access permission</a> + </li> + <li> + <a href="#Query">Constructing the query</a> + </li> + <li> + <a href="#DisplayResults">Displaying query results</a> + </li> + <li> + <a href="#GettingResults">Getting data from query results</a> + </li> + </ol> + </li> + <li> + <a href="#Permissions">Content Provider Permissions</a> + </li> + <li> + <a href="#Modifications">Inserting, Updating, and Deleting Data</a> + <ol> + <li> + <a href="#Inserting">Inserting data</a> + </li> + <li> + <a href="#Updating">Updating data</a> + </li> + <li> + <a href="#Deleting">Deleting data</a> + </li> + </ol> + </li> + <li> + <a href="#DataTypes">Provider Data Types</a> + </li> + <li> + <a href="#AltForms">Alternative Forms of Provider Access</a> + <ol> + <li> + <a href="#Batch">Batch access</a> + </li> + <li> + <a href="#Intents">Data access via intents</a> + </li> + </ol> + </li> + <li> + <a href="#ContractClasses">Contract Classes</a> + </li> + <li> + <a href="#MIMETypeReference">MIME Type Reference</a> + </li> +</ol> + + <!-- Key Classes --> +<h2>Key classes</h2> + <ol> + <li> + {@link android.content.ContentProvider} + </li> + <li> + {@link android.content.ContentResolver} + </li> + <li> + {@link android.database.Cursor} + </li> + <li> + {@link android.net.Uri} + </li> + </ol> + + <!-- Related Samples --> +<h2>Related Samples</h2> + <ol> + <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> + + <!-- See also --> +<h2>See also</h2> + <ol> + <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> +</div> +</div> + + <!-- Intro paragraphs --> +<p> + A content provider manages access to a central repository of data. The provider and + is part of an Android application, which often provides its own UI for working with + the data. However, content providers are primarily intended to be used by other + applications, which access the provider using a provider client object. Together, providers + and provider clients offer a consistent, standard interface to data that also handles + inter-process communication and secure data access. +</p> +<p> + This topic describes the basics of the following: +</p> + <ul> + <li>How content providers work.</li> + <li>The API you use retrieve data from a content provider.</li> + <li>The API you use to insert, update, or delete data in a content provider.</li> + <li>Other API features that facilitate working with providers.</li> + </ul> + + <!-- Basics --> +<h2 id="Basics">Overview</h2> +<p> + A content provider presents data to external applications as one or more tables that are + similar to the tables found in a relational database. A row represents an instance of some type + of data the provider collects, and each row in the column represents an individual piece of + data collected for an instance. +</p> +<p> + For example, one of the built-in providers in the Android platform is the user dictionary, which + stores the spellings of non-standard words that the user wants to keep. Table 1 illustrates what + the data might look like in this provider's table: +</p> +<p class="table-caption"> + <strong>Table 1:</strong> Sample user dictionary table. +</p> +<table id="table1" style="width: 50%;"> + <tr> + <th style="width:20%" align="center" scope="col">word</th> + <th style="width:20%" align="center" scope="col">app id</th> + <th style="width:20%" align="center" scope="col">frequency</th> + <th style="width:20%" align="center" scope="col">locale</th> + <th style="width:20%" align="center" scope="col">_ID</th> + </tr> + <tr> + <td align="center" scope="row">mapreduce</td> + <td align="center">user1</td> + <td align="center">100</td> + <td align="center">en_US</td> + <td align="center">1</td> + </tr> + <tr> + <td align="center" scope="row">precompiler</td> + <td align="center">user14</td> + <td align="center">200</td> + <td align="center">fr_FR</td> + <td align="center">2</td> + </tr> + <tr> + <td align="center" scope="row">applet</td> + <td align="center">user2</td> + <td align="center">225</td> + <td align="center">fr_CA</td> + <td align="center">3</td> + </tr> + <tr> + <td align="center" scope="row">const</td> + <td align="center">user1</td> + <td align="center">255</td> + <td align="center">pt_BR</td> + <td align="center">4</td> + </tr> + <tr> + <td align="center" scope="row">int</td> + <td align="center">user5</td> + <td align="center">100</td> + <td align="center">en_UK</td> + <td align="center">5</td> + </tr> +</table> +<p> + In table 1, each row represents an instance of a word that might not be + found in a standard dictionary. Each column represents some data for that word, such as the + locale in which it was first encountered. The column headers are column names that are stored in + the provider. To refer to a row's locale, you refer to its <code>locale</code> column. For + this provider, the <code>_ID</code> column serves as a "primary key" column that + the provider automatically maintains. +</p> +<p class="note"> + <strong>Note:</strong> A provider isn't required to have a primary key, and it isn't required + to use <code>_ID</code> as the column name of a primary key if one is present. However, + if you want to bind data from a provider to a {@link android.widget.ListView}, one of the + column names has to be <code>_ID</code>. This requirement is explained in more detail in the + section <a href="#DisplayResults">Displaying query results</a>. +</p> +<h3 id="ClientProvider">Accessing a provider</h3> +<p> + An application accesses the data from a content provider with + a {@link android.content.ContentResolver} client object. This object has methods that call + identically-named methods in the provider object, an instance of one of the concrete + subclasses of {@link android.content.ContentProvider}. The + {@link android.content.ContentResolver} methods provide the basic + "CRUD" (create, retrieve, update, and delete) functions of persistent storage. +</p> +<p> + The {@link android.content.ContentResolver} object in the client application's + process and the {@link android.content.ContentProvider} object in the application that owns + the provider automatically handle inter-process communication. + {@link android.content.ContentProvider} also acts as an abstraction layer between its + repository of data and the external appearance of data as tables. +</p> +<p class="note"> + <strong>Note:</strong> To access a provider, your application usually has to request specific + permissions in its manifest file. This is described in more detail in the section + <a href="#Permissions">Content Provider Permissions</a> +</p> +<p> + For example, to get a list of the words and their locales from the User Dictionary Provider, + you call {@link android.content.ContentResolver#query(Uri, String[], String, String[], String) + ContentResolver.query()}. + The {@link android.content.ContentResolver#query(Uri, String[], String, String[], String) + query()} method calls the + {@link android.content.ContentProvider#query(Uri, String[], String, String[], String) + ContentProvider.query()} method defined by the User Dictionary Provider. The following lines + of code show a + {@link android.content.ContentResolver#query(Uri, String[], String, String[], String) + ContentResolver.query()} call: +<p> +<pre> +// Queries the user dictionary and returns results +mCursor = getContentResolver().query( + UserDictionary.Words.CONTENT_URI, // The content URI of the words table + mProjection, // The columns to return for each row + mSelectionClause // Selection criteria + mSelectionArgs, // Selection criteria + mSortOrder); // The sort order for the returned rows +</pre> +<p> + Table 2 shows how the arguments to + {@link android.content.ContentResolver#query(Uri, String[], String, String[], String) + query(Uri,projection,selection,selectionArgs,sortOrder)} match an SQL SELECT statement: +</p> +<p class="table-caption"> + <strong>Table 2:</strong> Query() compared to SQL query. +</p> +<table id="table2" style="width: 75%;"> + <tr> + <th style="width:25%" align="center" scope="col">query() argument</th> + <th style="width:25%" align="center" scope="col">SELECT keyword/parameter</th> + <th style="width:50%" align="center" scope="col">Notes</th> + </tr> + <tr> + <td align="center"><code>Uri</code></td> + <td align="center"><code>FROM <em>table_name</em></code></td> + <td><code>Uri</code> maps to the table in the provider named <em>table_name</em>.</td> + </tr> + <tr> + <td align="center"><code>projection</code></td> + <td align="center"><code><em>col,col,col,...</em></code></td> + <td> + <code>projection</code> is an array of columns that should be included for each row + retrieved. + </td> + </tr> + <tr> + <td align="center"><code>selection</code></td> + <td align="center"><code>WHERE <em>col</em> = <em>value</em></code></td> + <td><code>selection</code> specifies the criteria for selecting rows.</td> + </tr> + <tr> + <td align="center"><code>selectionArgs</code></td> + <td align="center"> + (No exact equivalent. Selection arguments replace <code>?</code> placeholders in the + selection clause.) + </td> + </tr> + <tr> + <td align="center"><code>sortOrder</code></td> + <td align="center"><code>ORDER BY <em>col,col,...</em></code></td> + <td> + <code>sortOrder</code> specifies the order in which rows appear in the returned + {@link android.database.Cursor}. + </td> + </tr> +</table> +<h3 id="ContentURIs">Content URIs</h3> +<p> + A <strong>content URI</strong> is a URI that identifies data in a provider. Content URIs + include the symbolic name of the entire provider (its <strong>authority</strong>) and a + name that points to a table (a <strong>path</strong>). When you call + a client method to access a table in a provider, the content URI for the table is one of + the arguments. +</p> +<p> + In the preceding lines of code, the constant + {@link android.provider.UserDictionary.Words#CONTENT_URI} contains the content URI of + the user dictionary's "words" table. The {@link android.content.ContentResolver} + object parses out the URI's authority, and uses it to "resolve" the provider by + comparing the authority to a system table of known providers. The + {@link android.content.ContentResolver} can then dispatch the query arguments to the correct + provider. +</p> +<p> + The {@link android.content.ContentProvider} uses the path part of the content URI to choose the + table to access. A provider usually has a <strong>path</strong> for each table it exposes. +</p> +<p> + In the previous lines of code, the full URI for the "words" table is: +</p> +<pre> +content://user_dictionary/words +</pre> +<p> + where the <code>user_dictionary</code> string is the provider's authority, and + <code>words</code> string is the table's path. The string + <code>content://</code> (the <strong>scheme</strong>) is always present, + and identifies this as a content URI. +</p> +<p> + Many providers allow you to access a single row in a table by appending an ID value + to the end of the URI. For example, to retrieve a row whose <code>_ID</code> is + <code>4</code> from user dictionary, you can use this content URI: +</p> +<pre> +Uri singleUri = ContentUri.withAppendedId(UserDictionary.Words.CONTENT_URI,4); +</pre> +<p> + You often use id values when you've retrieved a set of rows and then want to update or delete + one of them. +</p> +<p class="note"> + <strong>Note:</strong> The {@link android.net.Uri} and {@link android.net.Uri.Builder} classes + contain convenience methods for constructing well-formed Uri objects from strings. The + {@link android.content.ContentUris} contains convenience methods for appending id values to + a URI. The previous snippet uses {@link android.content.ContentUris#withAppendedId(Uri, long) + withAppendedId()} to append an id to the UserDictionary content URI. +</p> + + + <!-- Retrieving Data from the Provider --> +<h2 id="SimpleQuery">Retrieving Data from the Provider</h2> +<p> + This section describes how to retrieve data from a provider, using the User Dictionary Provider + as an example. +</p> +<p class="note"> + For the sake of clarity, the code snippets in this section call + {@link android.content.ContentResolver#query(Uri, String[], String, String[], String) + ContentResolver.query()} on the "UI thread"". In actual code, however, you should + do queries asynchronously on a separate thread. One way to do this is to use the + {@link android.content.CursorLoader} class, which is described + in more detail in the <a href="{@docRoot}guide/topics/fundamentals/loaders.html"> + Loaders</a> guide. Also, the lines of code are snippets only; they don't show a complete + application. +</p> +<p> + To retrieve data from a provider, follow these basic steps: +</p> +<ol> + <li> + Request the read access permission for the provider. + </li> + <li> + Define the code that sends a query to the provider. + </li> +</ol> +<h3 id="RequestPermissions">Requesting read access permission</h3> +<p> + To retrieve data from a provider, your application needs "read access permission" for the + provider. You can't request this permission at run-time; instead, you have to specify that + you need this permission in your manifest, using the + <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"> + <uses-permission></a></code> element and the exact permission name defined by the + provider. When you specify this element in your manifest, you are in effect "requesting" this + permission for your application. When users install your application, they implicitly grant + this request. +</p> +<p> + To find the exact name of the read access permission for the provider you're using, as well + as the names for other access permissions used by the provider, look in the provider's + documentation. +</p> +<p> + The role of permissions in accessing providers is described in more detail in the section + <a href="#Permissions">Content Provider Permissions</a>. +</p> +<p> + The User Dictionary Provider defines the permission + <code>android.permission.READ_USER_DICTIONARY</code> in its manifest file, so an + application that wants to read from the provider must request this permission. +</p> +<!-- Constructing the query --> +<h3 id="Query">Constructing the query</h3> +<p> + The next step in retrieving data a provider is to construct a query. This first snippet + defines some variables for accessing the User Dictionary Provider: +</p> +<pre class="prettyprint"> + +// A "projection" defines the columns that will be returned for each row +String[] mProjection = +{ + UserDictionary.Words._ID, // Contract class constant for the _ID column name + UserDictionary.Words.WORD, // Contract class constant for the word column name + UserDictionary.Words.LOCALE // Contract class constant for the locale column name +}; + +// Defines a string to contain the selection clause +String mSelectionClause = null; + +// Initializes an array to contain selection arguments +String[] mSelectionArgs = {""}; + +</pre> +<p> + The next snippet shows how to use + {@link android.content.ContentResolver#query(Uri, String[], String, String[], String) + ContentResolver.query()}, using the User Dictionary Provider as an example. + A provider client query is similar to an SQL query, and it contains a set of columns to return, + a set of selection criteria, and a sort order. +</p> +<p> + The set of columns that the query should return is called a <strong>projection</strong> + (the variable <code>mProjection</code>). +</p> +<p> + The expression that specifies the rows to retrieve is split into a selection clause and + selection arguments. The selection clause is a combination of logical and Boolean expressions, + column names, and values (the variable <code>mSelection</code>). If you specify the replaceable + parameter <code>?</code> instead of a value, the query method retrieves the value from the + selection arguments array (the variable <code>mSelectionArgs</code>). +</p> +<p> + In the next snippet, if the user doesn't enter a word, the selection clause is set to + <code>null</code>, and the query returns all the words in the provider. If the user enters + a word, the selection clause is set to <code>UserDictionary.Words.Word + " = ?"</code> and + the first element of selection arguments array is set to the word the user enters. +</p> +<pre class="prettyprint"> +/* + * This defines a one-element String array to contain the selection argument. + */ +String[] mSelectionArgs = {""}; + +// Gets a word from the UI +mSearchString = mSearchWord.getText().toString(); + +// Remember to insert code here to check for invalid or malicious input. + +// If the word is the empty string, gets everything +if (TextUtils.isEmpty(mSearchString)) { + // Setting the selection clause to null will return all words + mSelectionClause = null; + mSelectionArgs[0] = ""; + +} else { + // Constructs a selection clause that matches the word that the user entered. + mSelectionClause = " = ?"; + + // Moves the user's input string to the selection arguments. + mSelectionArgs[0] = mSearchString; + +} + +// Does a query against the table and returns a Cursor object +mCursor = getContentResolver().query( + UserDictionary.Words.CONTENT_URI, // The content URI of the words table + mProjection, // The columns to return for each row + mSelectionClause // Either null, or the word the user entered + mSelectionArgs, // Either empty, or the string the user entered + mSortOrder); // The sort order for the returned rows + +// Some providers return null if an error occurs, others throw an exception +if (null == mCursor) { + /* + * Insert code here to handle the error. Be sure not to use the cursor! You may want to + * call android.util.Log.e() to log this error. + * + */ +// If the Cursor is empty, the provider found no matches +} else if (mCursor.getCount() < 1) { + + /* + * Insert code here to notify the user that the search was unsuccessful. This isn't necessarily + * an error. You may want to offer the user the option to insert a new row, or re-type the + * search term. + */ + +} else { + // Insert code here to do something with the results + +} +</pre> +<p> + This query is analogous to the SQL statement: +</p> +<pre> +SELECT _ID, word, frequency, locale FROM words WHERE word = <userinput> ORDER BY word ASC; +</pre> +<p> + In this SQL statement, the actual column names are used instead of contract class constants. +</p> +<h4 id="Injection">Protecting against malicious input</h4> +<p> + If the data managed by the content provider is in an SQL database, including external untrusted + data into raw SQL statements can lead to SQL injection. +</p> +<p> + Consider this selection clause: +</p> +<pre> +// Constructs a selection clause by concatenating the user's input to the column name +String mSelectionClause = "var = " + mUserInput; +</pre> +<p> + If you do this, you're allowing the user to concatenate malicious SQL onto your SQL statement. + For example, the user could enter "nothing; DROP TABLE *;" for <code>mUserInput</code>, which + would result in the selection clause <code>var = nothing; DROP TABLE *;</code>. Since the + selection clause is treated as an SQL statement, this might cause the provider to erase all of + the tables in the underlying SQLite database (unless the provider is set up to catch + <a href="http://en.wikipedia.org/wiki/SQL_injection">SQL injection</a> attempts). +</p> +<p> + To avoid this problem, use a selection clause that uses <code>?</code> as a replaceable + parameter and a separate array of selection arguments. When you do this, the user input + is bound directly to the query rather than being interpreted as part of an SQL statement. + Because it's not treated as SQL, the user input can't inject malicious SQL. Instead of using + concatenation to include the user input, use this selection clause: +</p> +<pre> +// Constructs a selection clause with a replaceable parameter +String mSelectionClause = "var = ?"; +</pre> +<p> + Set up the array of selection arguments like this: +</p> +<pre> +// Defines an array to contain the selection arguments +String[] selectionArgs = {""}; +</pre> +<p> + Put a value in the selection arguments array like this: +</p> +<pre> +// Sets the selection argument to the user's input +selectionArgs[0] = mUserInput; +</pre> +<p> + A selection clause that uses <code>?</code> as a replaceable parameter and an array of + selection arguments array are preferred way to specify a selection, even the provider isn't + based on an SQL database. +</p> +<!-- Displaying the results --> +<h3 id="DisplayResults">Displaying query results</h3> +<p> + The {@link android.content.ContentResolver#query(Uri, String[], String, String[], String) + ContentResolver.query()} client method always returns a {@link android.database.Cursor} + containing the columns specified by the query's projection for the rows that match the query's + selection criteria. A {@link android.database.Cursor} object provides random read access to the + rows and columns it contains. Using {@link android.database.Cursor} methods, + you can iterate over the rows in the results, determine the data type of each column, get the + data out of a column, and examine other properties of the results. Some + {@link android.database.Cursor} implementations automatically update the object when the + provider's data changes, or trigger methods in an observer object when the + {@link android.database.Cursor} changes, or both. +</p> +<p class="note"> + <strong>Note:</strong> A provider may restrict access to columns based on the nature of the + object making the query. For example, the Contacts Provider restricts access for some columns to + sync adapters, so it won't return them to an activity or service. +</p> +<p> + If no rows match the selection criteria, the provider + returns a {@link android.database.Cursor} object for which + {@link android.database.Cursor#getCount() Cursor.getCount()} is 0 (an empty cursor). +</p> +<p> + If an internal error occurs, the results of the query depend on the particular provider. It may + choose to return <code>null</code>, or it may throw an {@link java.lang.Exception}. +</p> +<p> + Since a {@link android.database.Cursor} is a "list" of rows, a good way to display the + contents of a {@link android.database.Cursor} is to link it to a {@link android.widget.ListView} + via a {@link android.widget.SimpleCursorAdapter}. +</p> +<p> + The following snippet continues the code from the previous snippet. It creates a + {@link android.widget.SimpleCursorAdapter} object containing the {@link android.database.Cursor} + retrieved by the query, and sets this object to be the adapter for a + {@link android.widget.ListView}: +</p> +<pre class="prettyprint"> +// Defines a list of columns to retrieve from the Cursor and load into an output row +String[] mWordListColumns = +{ + UserDictionary.Words.WORD, // Contract class constant containing the word column name + UserDictionary.Words.LOCALE // Contract class constant containing the locale column name +}; + +// Defines a list of View IDs that will receive the Cursor columns for each row +int[] mWordListItems = { R.id.dictWord, R.id.locale}; + +// Creates a new SimpleCursorAdapter +mCursorAdapter = new SimpleCursorAdapter( + getApplicationContext(), // The application's Context object + R.layout.wordlistrow, // A layout in XML for one row in the ListView + mCursor, // The result from the query + mWordListColumns, // A string array of column names in the cursor + mWordListItems, // An integer array of view IDs in the row layout + 0); // Flags (usually none are needed) + +// Sets the adapter for the ListView +mWordList.setAdapter(mCursorAdapter); +</pre> +<p class="note"> + <strong>Note:</strong> To back a {@link android.widget.ListView} with a + {@link android.database.Cursor}, the cursor must contain a column named <code>_ID</code>. + Because of this, the query shown previously retrieves the <code>_ID</code> column for the + "words" table, even though the {@link android.widget.ListView} doesn't display it. + This restriction also explains why most providers have a <code>_ID</code> column for each of + their tables. +</p> + + <!-- Getting data from query results --> +<h3 id="GettingResults">Getting data from query results</h3> +<p> + Rather than simply displaying query results, you can use them for other tasks. For + example, you can retrieve spellings from the user dictionary and then look them up in + other providers. To do this, you iterate over the rows in the {@link android.database.Cursor}: +</p> +<pre class="prettyprint"> + +// Determine the column index of the column named "word" +int index = mCursor.getColumnIndex(UserDictionary.Words.WORD); + +/* + * Only executes if the cursor is valid. The User Dictionary Provider returns null if + * an internal error occurs. Other providers may throw an Exception instead of returning null. + */ + +if (mCursor != null) { + /* + * Moves to the next row in the cursor. Before the first movement in the cursor, the + * "row pointer" is -1, and if you try to retrieve data at that position you will get an + * exception. + */ + while (mCursor.moveToNext()) { + + // Gets the value from the column. + newWord = mCursor.getString(index); + + // Insert code here to process the retrieved word. + + ... + + // end of while loop + } +} else { + + // Insert code here to report an error if the cursor is null or the provider threw an exception. +} +</pre> +<p> + {@link android.database.Cursor} implementations contain several "get" methods for + retrieving different types of data from the object. For example, the previous snippet + uses {@link android.database.Cursor#getString(int) getString()}. They also have a + {@link android.database.Cursor#getType(int) getType()} method that returns a value indicating + the data type of the column. +</p> + + + <!-- Requesting permissions --> +<h2 id="Permissions">Content Provider Permissions</h2> +<p> + A provider's application can specify permissions that other applications must have in order to + access the provider's data. These permissions ensure that the user knows what data + an application will try to access. Based on the provider's requirements, other applications + request the permissions they need in order to access the provider. End users see the requested + permissions when they install the application. +</p> +<p> + If a provider's application doesn't specify any permissions, then other applications have no + access to the provider's data. However, components in the provider's application always have + full read and write access, regardless of the specified permissions. +</p> +<p> + As noted previously, the User Dictionary Provider requires the + <code>android.permission.READ_USER_DICTIONARY</code> permission to retrieve data from it. + The provider has the separate <code>android.permission.WRITE_USER_DICTIONARY</code> + permission for inserting, updating, or deleting data. +</p> +<p> + To get the permissions needed to access a provider, an application requests them with a + <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"> + <uses-permission></a></code> element in its manifest file. + When the Android Package Manager installs the application, a user must approve all of the + permissions the application requests. If the user approves all of them, Package Manager + continues the installation; if the user doesn't approve them, Package Manager + aborts the installation. +</p> +<p> + The following + <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"> + <uses-permission></a></code> element requests read access to the User Dictionary Provider: +</p> +<pre> + <uses-permission android:name="android.permission.READ_USER_DICTIONARY"> +</pre> +<p> + The impact of permissions on provider access is explained in more detail in the + <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a> guide. +</p> + + +<!-- Inserting, Updating, and Deleting Data --> +<h2 id="Modifications">Inserting, Updating, and Deleting Data</h2> +<p> + In the same way that you retrieve data from a provider, you also use the interaction between + a provider client and the provider's {@link android.content.ContentProvider} to modify data. + You call a method of {@link android.content.ContentResolver} with arguments that are passed to + the corresponding method of {@link android.content.ContentProvider}. The provider and provider + client automatically handle security and inter-process communication. +</p> +<h3 id="Inserting">Inserting data</h3> +<p> + To insert data into a provider, you call the + {@link android.content.ContentResolver#insert(Uri,ContentValues) ContentResolver.insert()} + method. This method inserts a new row into the provider and returns a content URI for that row. + This snippet shows how to insert a new word into the User Dictionary Provider: +</p> +<pre class="prettyprint"> +// Defines a new Uri object that receives the result of the insertion +Uri mNewUri; + +... + +// Defines an object to contain the new values to insert +ContentValues mNewValues = new ContentValues(); + +/* + * Sets the values of each column and inserts the word. The arguments to the "put" + * method are "column name" and "value" + */ +mNewValues.put(UserDictionary.Words.APP_ID, "example.user"); +mNewValues.put(UserDictionary.Words.LOCALE, "en_US"); +mNewValues.put(UserDictionary.Words.WORD, "insert"); +mNewValues.put(UserDictionary.Words.FREQUENCY, "100"); + +mNewUri = getContentResolver().insert( + UserDictionary.Word.CONTENT_URI, // the user dictionary content URI + mNewValues // the values to insert +); +</pre> +<p> + The data for the new row goes into a single {@link android.content.ContentValues} object, which + is similar in form to a one-row cursor. The columns in this object don't need to have the + same data type, and if you don't want to specify a value at all, you can set a column + to <code>null</code> using {@link android.content.ContentValues#putNull(String) + ContentValues.putNull()}. +</p> +<p> + The snippet doesn't add the <code>_ID</code> column, because this column is maintained + automatically. The provider assigns a unique value of <code>_ID</code> to every row that is + added. Providers usually use this value as the table's primary key. +</p> +<p> + The content URI returned in <code>newUri</code> identifies the newly-added row, with + the following format: +</p> +<pre> +content://user_dictionary/words/<id_value> +</pre> +<p> + The <code><id_value></code> is the contents of <code>_ID</code> for the new row. + Most providers can detect this form of content URI automatically and then perform the requested + operation on that particular row. +</p> +<p> + To get the value of <code>_ID</code> from the returned {@link android.net.Uri}, call + {@link android.content.ContentUris#parseId(Uri) ContentUris.parseId()}. +</p> +<h3 id="Updating">Updating data</h3> +<p> + To update a row, you use a {@link android.content.ContentValues} object with the updated + values just as you do with an insertion, and selection criteria just as you do with a query. + The client method you use is + {@link android.content.ContentResolver#update(Uri, ContentValues, String, String[]) + ContentResolver.update()}. You only need to add values to the + {@link android.content.ContentValues} object for columns you're updating. If you want to clear + the contents of a column, set the value to <code>null</code>. +</p> +<p> + The following snippet changes all the rows whose locale has the language "en" to a + have a locale of <code>null</code>. The return value is the number of rows that were updated: +</p> +<pre> +// Defines an object to contain the updated values +ContentValues mUpdateValues = new ContentValues(); + +// Defines selection criteria for the rows you want to update +String mSelectionClause = UserDictionary.Words.LOCALE + "LIKE ?"; +String[] mSelectionArgs = {"en_%"}; + +// Defines a variable to contain the number of updated rows +int mRowsUpdated = 0; + +... + +/* + * Sets the updated value and updates the selected words. + */ +mUpdateValues.putNull(UserDictionary.Words.LOCALE); + +mRowsUpdated = getContentResolver().update( + UserDictionary.Words.CONTENT_URI, // the user dictionary content URI + mUpdateValues // the columns to update + mSelectionClause // the column to select on + mSelectionArgs // the value to compare to +); +</pre> +<p> + You should also sanitize user input when you call + {@link android.content.ContentResolver#update(Uri, ContentValues, String, String[]) + ContentResolver.update()}. To learn more about this, read the section + <a href="#Injection">Protecting against malicious input</a>. +</p> +<h3 id="Deleting">Deleting data</h3> +<p> + Deleting rows is similar to retrieving row data: you specify selection criteria for the rows + you want to delete and the client method returns the number of deleted rows. + The following snippet deletes rows whose appid matches "user". The method returns the + number of deleted rows. +</p> +<pre> + +// Defines selection criteria for the rows you want to delete +String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?"; +String[] mSelectionArgs = {"user"}; + +// Defines a variable to contain the number of rows deleted +int mRowsDeleted = 0; + +... + +// Deletes the words that match the selection criteria +mRowsDeleted = getContentResolver().delete( + UserDictionary.Words.CONTENT_URI, // the user dictionary content URI + mSelectionClause // the column to select on + mSelectionArgs // the value to compare to +); +</pre> +<p> + You should also sanitize user input when you call + {@link android.content.ContentResolver#delete(Uri, String, String[]) + ContentResolver.delete()}. To learn more about this, read the section + <a href="#Injection">Protecting against malicious input</a>. +</p> +<!-- Provider Data Types --> +<h2 id="DataTypes">Provider Data Types</h2> +<p> + Content providers can offer many different data types. The User Dictionary Provider offers only + text, but providers can also offer the following formats: +</p> + <ul> + <li> + integer + </li> + <li> + long integer (long) + </li> + <li> + floating point + </li> + <li> + long floating point (double) + </li> + </ul> +<p> + Another data type that providers often use is Binary Large OBject (BLOB) implemented as a + 64KB byte array. You can see the available data types by looking at the + {@link android.database.Cursor} class "get" methods. +</p> +<p> + The data type for each column in a provider is usually listed in its documentation. + The data types for the User Dictionary Provider are listed in the reference documentation + for its contract class {@link android.provider.UserDictionary.Words} (contract classes are + described in the section <a href="#ContractClasses">Contract Classes</a>). + You can also determine the data type by calling {@link android.database.Cursor#getType(int) + Cursor.getType()}. +</p> +<p> + Providers also maintain MIME data type information for each content URI they define. You can + use the MIME type information to find out if your application can handle data that the + provider offers, or to choose a type of handling based on the MIME type. You usually need the + MIME type when you are working with a provider that contains complex + data structures or files. For example, the {@link android.provider.ContactsContract.Data} + table in the Contacts Provider uses MIME types to label the type of contact data stored in each + row. To get the MIME type corresponding to a content URI, call + {@link android.content.ContentResolver#getType(Uri) ContentResolver.getType()}. +</p> +<p> + The section <a href="#MIMETypeReference">MIME Type Reference</a> describes the + syntax of both standard and custom MIME types. +</p> + + +<!-- Alternative Forms of Provider Access --> +<h2 id="AltForms">Alternative Forms of Provider Access</h2> +<p> + Three alternative forms of provider access are important in application development: +</p> +<ul> + <li> + <a href="#Batch">Batch access</a>: You can create a batch of access calls with methods in + the {@link android.content.ContentProviderOperation} class, and then apply them with + {@link android.content.ContentResolver#applyBatch(String, ArrayList) + ContentResolver.applyBatch()}. + </li> + <li> + Asynchronous queries: You should do queries in a separate thread. One way to do this is to + use a {@link android.content.CursorLoader} object. The examples in the + <a href="{@docRoot}guide/topics/fundamentals/loaders.html">Loaders</a> guide demonstrate + how to do this. + </li> + <li> + <a href="#Intents">Data access via intents</a>: Although you can't send an intent + directly to a provider, you can send an intent to the provider's application, which is + usually the best-equipped to modify the provider's data. + </li> +</ul> +<p> + Batch access and modification via intents are described in the following sections. +</p> +<h3 id="Batch">Batch access</h3> +<p> + Batch access to a provider is useful for inserting a large number of rows, or for inserting + rows in multiple tables in the same method call, or in general for performing a set of + operations across process boundaries as a transaction (an atomic operation). +</p> +<p> + To access a provider in "batch mode", + you create an array of {@link android.content.ContentProviderOperation} objects and then + dispatch them to a content provider with + {@link android.content.ContentResolver#applyBatch(String, ArrayList) + ContentResolver.applyBatch()}. You pass the content provider's <em>authority</em> to this + method, rather than a particular content URI, which allows each + {@link android.content.ContentProviderOperation} object in the array to work against a + different table. A call to {@link android.content.ContentResolver#applyBatch(String, ArrayList) + ContentResolver.applyBatch()} returns an array of results. +</p> +<p> + The description of the {@link android.provider.ContactsContract.RawContacts} contract class + includes a code snippet that demonstrates batch insertion. The + <a href="{@docRoot}resources/samples/ContactManager/index.html">Contact Manager</a> + sample application contains an example of batch access in its <code>ContactAdder.java</code> + source file. +</p> +<div class="sidebox-wrapper"> +<div class="sidebox"> +<h2>Displaying data using a helper app</h2> +<p> + If your application <em>does</em> have access permissions, you still may want to use an + intent to display data in another application. For example, the Calendar application accepts an + {@link android.content.Intent#ACTION_VIEW} intent, which displays a particular date or event. + This allows you to display calendar information without having to create your own UI. + To learn more about this feature, see the + <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar Provider</a> guide. +</p> +<p> + The application to which you send the intent doesn't have to be the application + associated with the provider. For example, you can retrieve a contact from the + Contact Provider, then send an {@link android.content.Intent#ACTION_VIEW} intent + containing the content URI for the contact's image to an image viewer. +</p> +</div> +</div> +<h3 id="Intents">Data access via intents</h3> +<p> + Intents can provide indirect access to a content provider. You allow the user to access + data in a provider even if your application doesn't have access permissions, either by + getting a result intent back from an application that has permissions, or by activating an + application that has permissions and letting the user do work in it. +</p> +<h4>Getting access with temporary permissions</h4> +<p> + You can access data in a content provider, even if you don't have the proper access + permissions, by sending an intent to an application that does have the permissions and + receiving back a result intent containing "URI" permissions. + These are permissions for a specific content URI that last until the activity that receives + them is finished. The application that has permanent permissions grants temporary + permissions by setting a flag in the result intent: +</p> +<ul> + <li> + <strong>Read permission:</strong> + {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} + </li> + <li> + <strong>Write permission:</strong> + {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} + </li> +</ul> +<p class="note"> + <strong>Note:</strong> These flags don't give general read or write access to the provider + whose authority is contained in the content URI. The access is only for the URI itself. +</p> +<p> + A provider defines URI permissions for content URIs in its manifest, using the + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn"> + android:grantUriPermission</a></code> + attribute of the + {@code <a href="guide/topics/manifest/provider-element.html"><provider></a>} + element, as well as the + {@code <a href="guide/topics/manifest/grant-uri-permission-element.html"> + <grant-uri-permission></a>} child element of the + {@code <a href="guide/topics/manifest/provider-element.html"><provider></a>} + element. The URI permissions mechanism is explained in more detail in the + <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a> guide, + in the section "URI Permissions". +</p> +<p> + For example, you can retrieve data for a contact in the Contacts Provider, even if you don't + have the {@link android.Manifest.permission#READ_CONTACTS} permission. You might want to do + this in an application that sends e-greetings to a contact on his or her birthday. Instead of + requesting {@link android.Manifest.permission#READ_CONTACTS}, which gives you access to all of + the user's contacts and all of their information, you prefer to let the user control which + contacts are used by your application. To do this, you use the following process: +</p> +<ol> + <li> + Your application sends an intent containing the action + {@link android.content.Intent#ACTION_PICK} and the "contacts" MIME type + {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE}, using the + method {@link android.app.Activity#startActivityForResult(Intent, int) + startActivityForResult()}. + </li> + <li> + Because this intent matches the intent filter for the + People app's "selection" activity, the activity will come to the foreground. + </li> + <li> + In the selection activity, the user selects a + contact to update. When this happens, the selection activity calls + {@link android.app.Activity#setResult(int, Intent) setResult(resultcode, intent)} + to set up a intent to give back to your application. The intent contains the content URI + of the contact the user selected, and the "extras" flags + {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}. These flags grant URI + permission to your app to read data for the contact pointed to by the + content URI. The selection activity then calls {@link android.app.Activity#finish()} to + return control to your application. + </li> + <li> + Your activity returns to the foreground, and the system calls your activity's + {@link android.app.Activity#onActivityResult(int, int, Intent) onActivityResult()} + method. This method receives the result intent created by the selection activity in + the People app. + </li> + <li> + With the content URI from the result intent, you can read the contact's data + from the Contacts Provider, even though you didn't request permanent read access permission + to the provider in your manifest. You can then get the contact's birthday information + or his or her email address and then send the e-greeting. + </li> +</ol> +<h4>Using another application</h4> +<p> + A simple way to allow the user to modify data to which you don't have access permissions is to + activate an application that has permissions and let the user do the work there. +</p> +<p> + For example, the Calendar application accepts an + {@link android.content.Intent#ACTION_INSERT} intent, which allows you to activate the + application's insert UI. You can pass "extras" data in this intent, which the application + uses to pre-populate the UI. Because recurring events have a complex syntax, the preferred + way of inserting events into the Calendar Provider is to activate the Calendar app with an + {@link android.content.Intent#ACTION_INSERT} and then let the user insert the event there. +</p> +<!-- Contract Classes --> +<h2 id="ContractClasses">Contract Classes</h2> +<p> + A contract class defines constants that help applications work with the content URIs, column + names, intent actions, and other features of a content provider. Contract classes are not + included automatically with a provider; the provider's developer has to define them and then + make them available to other developers. Many of the providers included with the Android + platform have corresponding contract classes in the package {@link android.provider}. +</p> +<p> + For example, the User Dictionary Provider has a contract class + {@link android.provider.UserDictionary} containing content URI and column name constants. The + content URI for the "words" table is defined in the constant + {@link android.provider.UserDictionary.Words#CONTENT_URI UserDictionary.Words.CONTENT_URI}. + The {@link android.provider.UserDictionary.Words} class also contains column name constants, + which are used in the example snippets in this guide. For example, a query projection can be + defined as: +</p> +<pre> +String[] mProjection = +{ + UserDictionary.Words._ID, + UserDictionary.Words.WORD, + UserDictionary.Words.LOCALE +}; +</pre> +<p> + Another contract class is {@link android.provider.ContactsContract} for the Contacts Provider. + The reference documentation for this class includes example code snippets. One of its + subclasses, {@link android.provider.ContactsContract.Intents.Insert}, is a contract + class that contains constants for intents and intent data. +</p> + + +<!-- MIME Type Reference --> +<h2 id="MIMETypeReference">MIME Type Reference</h2> +<p> + Content providers can return standard MIME media types, or custom MIME type strings, or both. +</p> +<p> + MIME types have the format +</p> +<pre> +<em>type</em>/<em>subtype</em> +</pre> +<p> + For example, the well-known MIME type <code>text/html</code> has the <code>text</code> type and + the <code>html</code> subtype. If the provider returns this type for a URI, it means that a + query using that URI will return text containing HTML tags. +</p> +<p> + Custom MIME type strings, also called "vendor-specific" MIME types, have more + complex <em>type</em> and <em>subtype</em> values. The <em>type</em> value is always +</p> +<pre> +vnd.android.cursor.<strong>dir</strong> +</pre> +<p> + for multiple rows, or +</p> +<pre> +vnd.android.cursor.<strong>item</strong> +</pre> +<p> + for a single row. +</p> +<p> + The <em>subtype</em> is provider-specific. The Android built-in providers usually have a simple + subtype. For example, the when the Contacts application creates a row for a telephone number, + it sets the following MIME type in the row: +</p> +<pre> +vnd.android.cursor.item/phone_v2 +</pre> +<p> + Notice that the subtype value is simply <code>phone_v2</code>. +</p> +<p> + Other provider developers may create their own pattern of subtypes based on the provider's + authority and table names. For example, consider a provider that contains train timetables. + The provider's authority is <code>com.example.trains</code>, and it contains the tables + Line1, Line2, and Line3. In response to the content URI +</p> +<p> +<pre> +content://com.example.trains/Line1 +</pre> +<p> + for table Line1, the provider returns the MIME type +</p> +<pre> +vnd.android.cursor.<strong>dir</strong>/vnd.example.line1 +</pre> +<p> + In response to the content URI +</p> +<pre> +content://com.example.trains/Line2/5 +</pre> +<p> + for row 5 in table Line2, the provider returns the MIME type +</p> +<pre> +vnd.android.cursor.<strong>item</strong>/vnd.example.line2 +</pre> +<p> + Most content providers define contract class constants for the MIME types they use. The + Contacts Provider contract class {@link android.provider.ContactsContract.RawContacts}, + for example, defines the constant + {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} for the MIME type of + a single raw contact row. +</p> +<p> + Content URIs for single rows are described in the section + <a href="#ContentURIs">Content URIs</a>. +</p> diff --git a/docs/html/guide/topics/providers/content-provider-creating.jd b/docs/html/guide/topics/providers/content-provider-creating.jd new file mode 100644 index 0000000..4ebdb50 --- /dev/null +++ b/docs/html/guide/topics/providers/content-provider-creating.jd @@ -0,0 +1,1215 @@ +page.title=Creating a Content Provider +@jd:body +<div id="qv-wrapper"> +<div id="qv"> + + +<h2>In this document</h2> +<ol> + <li> + <a href="#DataStorage">Designing Data Storage</a> + </li> + <li> + <a href="#ContentURI">Designing Content URIs</a> + </li> + <li> + <a href="#ContentProvider">Implementing the ContentProvider Class</a> + <ol> + <li> + <a href="#RequiredAccess">Required Methods</a> + </li> + <li> + <a href="#Query">Implementing the query() method</a> + </li> + <li> + <a href="#Insert">Implementing the insert() method</a> + </li> + <li> + <a href="#Delete">Implementing the delete() method</a> + </li> + <li> + <a href="#Update">Implementing the update() method</a> + </li> + <li> + <a href="#OnCreate">Implementing the onCreate() method</a> + </li> + </ol> + </li> + <li> + <a href="#MIMETypes">Implementing Content Provider MIME Types</a> + <ol> + <li> + <a href="#TableMIMETypes">MIME types for tables</a> + </li> + <li> + <a href="#FileMIMETypes">MIME types for files</a> + </li> + </ol> + </li> + <li> + <a href="#ContractClass">Implementing a Contract Class</a> + </li> + <li> + <a href="#Permissions">Implementing Content Provider Permissions</a> + </li> + <li> + <a href="#ProviderElement">The <provider> Element</a> + </li> + <li> + <a href="#Intents">Intents and Data Access</a> + </li> +</ol> +<h2>Key classes</h2> + <ol> + <li> + {@link android.content.ContentProvider} + </li> + <li> + {@link android.database.Cursor} + </li> + <li> + {@link android.net.Uri} + </li> + </ol> +<h2>Related Samples</h2> + <ol> + <li> + <a + href="{@docRoot}resources/samples/NotePad/index.html"> + Note Pad sample application + </a> + </li> + </ol> +<h2>See also</h2> + <ol> + <li> + <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> + Content Provider Basics</a> + </li> + <li> + <a href="{@docRoot}guide/topics/providers/calendar-provider.html"> + Calendar Provider</a> + </li> + </ol> +</div> +</div> + + +<p> + A content provider manages access to a central repository of data. You implement a + provider as one or more classes in an Android application, along with elements in + the manifest file. One of your classes implements a subclass + {@link android.content.ContentProvider}, which is the interface between your provider and + other applications. Although content providers are meant to make data available to other + applications, you may of course have activities in your application that allow the user + to query and modify the data managed by your provider. +</p> +<p> + The rest of this topic is a basic list of steps for building a content provider and a list + of APIs to use. +</p> + + +<!-- Before You Start Building --> +<h2 id="BeforeYouStart">Before You Start Building</h2> +<p> + Before you start building a provider, do the following: +</p> +<ol> + <li> + <strong>Decide if you need a content provider</strong>. You need to build a content + provider if you want to provide one or more of the following features: + <ul> + <li>You want to offer complex data or files to other applications.</li> + <li>You want to allow users to copy complex data from your app into other apps.</li> + <li>You want to provide custom search suggestions using the search framework.</li> + </ul> + <p> + You <em>don't</em> need a provider to use an SQLite database if the use is entirely within + your own application. + </p> + </li> + <li> + If you haven't done so already, read the topic + <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> + Content Provider Basics</a> to learn more about providers. + </li> +</ol> +<p> + Next, follow these steps to build your provider: +</p> +<ol> + <li> + Design the raw storage for your data. A content provider offers data in two ways: + <dl> + <dt> + File data + </dt> + <dd> + Data that normally goes into files, such as + photos, audio, or videos. Store the files in your application's private + space. In response to a request for a file from another application, your + provider can offer a handle to the file. + </dd> + <dt> + "Structured" data + </dt> + <dd> + Data that normally goes into a database, array, or similar structure. + Store the data in a form that's compatible with tables of rows and columns. A row + represents an entity, such as a person or an item in inventory. A column represents + some data for the entity, such a person's name or an item's price. A common way to + store this type of data is in an SQLite database, but you can use any type of + persistent storage. To learn more about the storage types available in the + Android system, see the section <a href="#DataStorage"> + Designing Data Storage</a>. + </dd> + </dl> + </li> + <li> + Define a concrete implementation of the {@link android.content.ContentProvider} class and + its required methods. This class is the interface between your data and the rest of the + Android system. For more information about this class, see the section + <a href="#ContentProvider">Implementing the ContentProvider Class</a>. + </li> + <li> + Define the provider's authority string, its content URIs, and column names. If you want + the provider's application to handle intents, also define intent actions, extras data, + and flags. Also define the permissions that you will require for applications that want + to access your data. You should consider defining all of these values as constants in a + separate contract class; later, you can expose this class to other developers. For more + information about content URIs, see the + section <a href="#ContentURI">Designing Content URIs</a>. + For more information about intents, see the + section <a href="#Intents">Intents and Data Access</a>. + </li> + <li> + Add other optional pieces, such as sample data or an implementation + of {@link android.content.AbstractThreadedSyncAdapter} that can synchronize data between + the provider and cloud-based data. + </li> +</ol> + + +<!-- Designing Data Storage --> +<h2 id="DataStorage">Designing Data Storage</h2> +<p> + A content provider is the interface to data saved in a structured format. Before you create + the interface, you must decide how to store the data. You can store the data in any form you + like, and then design the interface to read and write the data as necessary. +</p> +<p> + These are some of the data storage technologies that are available in Android: +</p> +<ul> + <li> + The Android system includes an SQLite database API that Android's own providers use + to store table-oriented data. The + {@link android.database.sqlite.SQLiteOpenHelper} class helps you create databases, and the + {@link android.database.sqlite.SQLiteDatabase} class is the base class for accessing + databases. + <p> + Remember that you don't have to use a database to implement your repository. A provider + appears externally as a set of tables, similar to a relational database, but this is + not a requirement for the provider's internal implementation. + </p> + </li> + <li> + For storing file data, Android has a variety of file-oriented APIs. + To learn more about file storage, read the topic + <a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a>. If you're + designing a provider that offers media-related data such as music or videos, you can + have a provider that combines table data and files. + </li> + <li> + For working with network-based data, use classes in {@link java.net} and + {@link android.net}. You can also synchronize network-based data to a local data + store such as a database, and then offer the data as tables or files. + The <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html"> + Sample Sync Adapter</a> sample application demonstrates this type of synchronization. + </li> +</ul> +<h3 id="DataDesign"> + Data design considerations +</h3> +<p> + Here are some tips for designing your provider's data structure: +</p> +<ul> + <li> + Table data should always have a "primary key" column that the provider maintains + as a unique numeric value for each row. You can use this value to link the row to related + rows in other tables (using it as a "foreign key"). Although you can use any name + for this column, using {@link android.provider.BaseColumns#_ID BaseColumns._ID} is the best + choice, because linking the results of a provider query to a + {@link android.widget.ListView} requires one of the retrieved columns to have the name + <code>_ID</code>. + </li> + <li> + If you want to provide bitmap images or other very large pieces of file-oriented data, store + the data in a file and then provide it indirectly rather than storing it directly in a + table. If you do this, you need to tell users of your provider that they need to use a + {@link android.content.ContentResolver} file method to access the data. + </li> + <li> + Use the Binary Large OBject (BLOB) data type to store data that varies in size or has a + varying structure. For example, you can use a BLOB column to store a + <a href="http://code.google.com/p/protobuf">protocol buffer</a> or + <a href="http://www.json.org">JSON structure</a>. + <p> + You can also use a BLOB to implement a <em>schema-independent</em> table. In + this type of table, you define a primary key column, a MIME type column, and one or + more generic columns as BLOB. The meaning of the data in the BLOB columns is indicated + by the value in the MIME type column. This allows you to store different row types in + the same table. The Contacts Provider's "data" table + {@link android.provider.ContactsContract.Data} is an example of a schema-independent + table. + </p> + </li> +</ul> +<!-- Designing Content URIs --> +<h2 id="ContentURI">Designing Content URIs</h2> +<p> + A <strong>content URI</strong> is a URI that identifies data in a provider. Content URIs include + the symbolic name of the entire provider (its <strong>authority</strong>) and a + name that points to a table or file (a <strong>path</strong>). The optional id part points to + an individual row in a table. Every data access method of + {@link android.content.ContentProvider} has a content URI as an argument; this allows you to + determine the table, row, or file to access. +</p> +<p> + The basics of content URIs are described in the topic + <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> + Content Provider Basics</a>. +</p> +<h3>Designing an authority</h3> +<p> + A provider usually has a single authority, which serves as its Android-internal name. To + avoid conflicts with other providers, you should use Internet domain ownership (in reverse) + as the basis of your provider authority. Because this recommendation is also true for Android + package names, you can define your provider authority as an extension of the name + of the package containing the provider. For example, if your Android package name is + <code>com.example.<appname></code>, you should give your provider the + authority <code>com.example.<appname>.provider</code>. +</p> +<h3>Designing a path structure</h3> +<p> + Developers usually create content URIs from the authority by appending paths that point to + individual tables. For example, if you have two tables <em>table1</em> and + <em>table2</em>, you combine the authority from the previous example to yield the + content URIs + <code>com.example.<appname>.provider/table1</code> and + <code>com.example.<appname>.provider/table2</code>. Paths aren't + limited to a single segment, and there doesn't have to be a table for each level of the path. +</p> +<h3>Handling content URI IDs</h3> +<p> + By convention, providers offer access to a single row in a table by accepting a content URI + with an ID value for the row at the end of the URI. Also by convention, providers match the + ID value to the table's <code>_ID</code> column, and perform the requested access against the + row that matches. +</p> +<p> + This convention facilitates a common design pattern for apps accessing a provider. The app + does a query against the provider and displays the resulting {@link android.database.Cursor} + in a {@link android.widget.ListView} using a {@link android.widget.CursorAdapter}. + The definition of {@link android.widget.CursorAdapter} requires one of the columns in the + {@link android.database.Cursor} to be <code>_ID</code> +</p> +<p> + The user then picks one of the displayed rows from the UI in order to look at or modify the + data. The app gets the corresponding row from the {@link android.database.Cursor} backing the + {@link android.widget.ListView}, gets the <code>_ID</code> value for this row, appends it to + the content URI, and sends the access request to the provider. The provider can then do the + query or modification against the exact row the user picked. +</p> +<h3>Content URI patterns</h3> +<p> + To help you choose which action to take for an incoming content URI, the provider API includes + the convenience class {@link android.content.UriMatcher}, which maps content URI "patterns" to + integer values. You can use the integer values in a <code>switch</code> statement that + chooses the desired action for the content URI or URIs that match a particular pattern. +</p> +<p> + A content URI pattern matches content URIs using wildcard characters: +</p> + <ul> + <li> + <strong><code>*</code>:</strong> Matches a string of any valid characters of any length. + </li> + <li> + <strong><code>#</code>:</strong> Matches a string of numeric characters of any length. + </li> + </ul> +<p> + As an example of designing and coding content URI handling, consider a provider with the + authority <code>com.example.app.provider</code> that recognizes the following content URIs + pointing to tables: +</p> +<ul> + <li> + <code>content://com.example.app.provider/table1</code>: A table called <code>table1</code>. + </li> + <li> + <code>content://com.example.app.provider/table2/dataset1</code>: A table called + <code>dataset1</code>. + </li> + <li> + <code>content://com.example.app.provider/table2/dataset2</code>: A table called + <code>dataset2</code>. + </li> + <li> + <code>content://com.example.app.provider/table3</code>: A table called <code>table3</code>. + </li> +</ul> +<p> + The provider also recognizes these content URIs if they have a row ID appended to them, as + for example <code>content://com.example.app.provider/table3/1</code> for the row identified by + <code>1</code> in <code>table3</code>. +</p> +<p> + The following content URI patterns would be possible: +</p> +<dl> + <dt> + <code>content://com.example.app.provider/*</code> + </dt> + <dd> + Matches any content URI in the provider. + </dd> + <dt> + <code>content://com.example.app.provider/table2/*</code>: + </dt> + <dd> + Matches a content URI for the tables <code>dataset1</code> + and <code>dataset2</code>, but doesn't match content URIs for <code>table1</code> or + <code>table3</code>. + </dd> + <dt> + <code>content://com.example.app.provider/table3/#</code>: Matches a content URI + for single rows in <code>table3</code>, such as + <code>content://com.example.app.provider/table3/6</code> for the row identified by + <code>6</code>. + </dt> +</dl> +<p> + The following code snippet shows how the methods in {@link android.content.UriMatcher} work. + This code handles URIs for an entire table differently from URIs for a + single row, by using the content URI pattern + <code>content://<authority>/<path></code> for tables, and + <code>content://<authority>/<path>/<id></code> for single rows. +</p> +<p> + The method {@link android.content.UriMatcher#addURI(String, String, int) addURI()} maps an + authority and path to an integer value. The method android.content.UriMatcher#match(Uri) + match()} returns the integer value for a URI. A <code>switch</code> statement + chooses between querying the entire table, and querying for a single record: +</p> +<pre class="prettyprint"> +public class ExampleProvider extends ContentProvider { +... + // Creates a UriMatcher object. + private static final UriMatcher sUriMatcher; +... + /* + * The calls to addURI() go here, for all of the content URI patterns that the provider + * should recognize. For this snippet, only the calls for table 3 are shown. + */ +... + /* + * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used + * in the path + */ + sUriMatcher.addURI("com.example.app.provider", "table3", 1); + + /* + * Sets the code for a single row to 2. In this case, the "#" wildcard is + * used. "content://com.example.app.provider/table3/3" matches, but + * "content://com.example.app.provider/table3 doesn't. + */ + sUriMatcher.addURI("com.example.app.provider", "table3/#", 2); +... + // Implements ContentProvider.query() + public Cursor query( + Uri uri, + String[] projection, + String selection, + String[] selectionArgs, + String sortOrder) { +... + /* + * Choose the table to query and a sort order based on the code returned for the incoming + * URI. Here, too, only the statements for table 3 are shown. + */ + switch (sUriMatcher.match(uri)) { + + + // If the incoming URI was for all of table3 + case 1: + + if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC"; + break; + + // If the incoming URI was for a single row + case 2: + + /* + * Because this URI was for a single row, the _ID value part is + * present. Get the last path segment from the URI; this is the _ID value. + * Then, append the value to the WHERE clause for the query + */ + selection = selection + "_ID = " uri.getLastPathSegment(); + break; + + default: + ... + // If the URI is not recognized, you should do some error handling here. + } + // call the code to actually do the query + } +</pre> +<p> + Another class, {@link android.content.ContentUris}, provides convenience methods for working + with the <code>id</code> part of content URIs. The classes {@link android.net.Uri} and + {@link android.net.Uri.Builder} include convenience methods for parsing existing + {@link android.net.Uri} objects and building new ones. +</p> + +<!-- Implementing the ContentProvider class --> +<h2 id="ContentProvider">Implementing the ContentProvider Class</h2> +<p> + The {@link android.content.ContentProvider} instance manages access + to a structured set of data by handling requests from other applications. All forms + of access eventually call {@link android.content.ContentResolver}, which then calls a concrete + method of {@link android.content.ContentProvider} to get access. +</p> +<h3 id="RequiredAccess">Required methods</h3> +<p> + The abstract class {@link android.content.ContentProvider} defines six abstract methods that + you must implement as part of your own concrete subclass. All of these methods except + {@link android.content.ContentProvider#onCreate() onCreate()} are called by a client application + that is attempting to access your content provider: +</p> +<dl> + <dt> + {@link android.content.ContentProvider#query(Uri, String[], String, String[], String) + query()} + </dt> + <dd> + Retrieve data from your provider. Use the arguments to select the table to + query, the rows and columns to return, and the sort order of the result. + Return the data as a {@link android.database.Cursor} object. + </dd> + <dt> + {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} + </dt> + <dd> + Insert a new row into your provider. Use the arguments to select the + destination table and to get the column values to use. Return a content URI for the + newly-inserted row. + </dd> + <dt> + {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[]) + update()} + </dt> + <dd> + Update existing rows in your provider. Use the arguments to select the table and rows + to update and to get the updated column values. Return the number of rows updated. + </dd> + <dt> + {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} + </dt> + <dd> + Delete rows from your provider. Use the arguments to select the table and the rows to + delete. Return the number of rows deleted. + </dd> + <dt> + {@link android.content.ContentProvider#getType(Uri) getType()} + </dt> + <dd> + Return the MIME type corresponding to a content URI. This method is described in more + detail in the section <a href="#MIMETypes">Implementing Content Provider MIME Types</a>. + </dd> + <dt> + {@link android.content.ContentProvider#onCreate() onCreate()} + </dt> + <dd> + Initialize your provider. The Android system calls this method immediately after it + creates your provider. Notice that your provider is not created until a + {@link android.content.ContentResolver} object tries to access it. + </dd> +</dl> +<p> + Notice that these methods have the same signature as the identically-named + {@link android.content.ContentResolver} methods. +</p> +<p> + Your implementation of these methods should account for the following: +</p> +<ul> + <li> + All of these methods except {@link android.content.ContentProvider#onCreate() onCreate()} + can be called by multiple threads at once, so they must be thread-safe. To learn + more about multiple threads, see the topic + <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html"> + Processes and Threads</a>. + </li> + <li> + Avoid doing lengthy operations in {@link android.content.ContentProvider#onCreate() + onCreate()}. Defer initialization tasks until they are actually needed. + The section <a href="#OnCreate">Implementing the onCreate() method</a> + discusses this in more detail. + </li> + <li> + Although you must implement these methods, your code does not have to do anything except + return the expected data type. For example, you may want to prevent other applications + from inserting data into some tables. To do this, you can ignore the call to + {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} and return + 0. + </li> +</ul> +<h3 id="Query">Implementing the query() method</h3> +<p> + The + {@link android.content.ContentProvider#query(Uri, String[], String, String[], String) + ContentProvider.query()} method must return a {@link android.database.Cursor} object, or if it + fails, throw an {@link java.lang.Exception}. If you are using an SQLite database as your data + storage, you can simply return the {@link android.database.Cursor} returned by one of the + <code>query()</code> methods of the {@link android.database.sqlite.SQLiteDatabase} class. + If the query does not match any rows, you should return a {@link android.database.Cursor} + instance whose {@link android.database.Cursor#getCount()} method returns 0. + You should return <code>null</code> only if an internal error occurred during the query process. +</p> +<p> + If you aren't using an SQLite database as your data storage, use one of the concrete subclasses + of {@link android.database.Cursor}. For example, the {@link android.database.MatrixCursor} class + implements a cursor in which each row is an array of {@link java.lang.Object}. With this class, + use {@link android.database.MatrixCursor#addRow(Object[]) addRow()} to add a new row. +</p> +<p> + Remember that the Android system must be able to communicate the {@link java.lang.Exception} + across process boundaries. Android can do this for the following exceptions that may be useful + in handling query errors: +</p> +<ul> + <li> + {@link java.lang.IllegalArgumentException} (You may choose to throw this if your provider + receives an invalid content URI) + </li> + <li> + {@link java.lang.NullPointerException} + </li> +</ul> +<h3 id="Insert">Implementing the insert() method</h3> +<p> + The {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} method adds a + new row to the appropriate table, using the values in the {@link android.content.ContentValues} + argument. If a column name is not in the {@link android.content.ContentValues} argument, you + may want to provide a default value for it either in your provider code or in your database + schema. +</p> +<p> + This method should return the content URI for the new row. To construct this, append the new + row's <code>_ID</code> (or other primary key) value to the table's content URI, using + {@link android.content.ContentUris#withAppendedId(Uri, long) withAppendedId()}. +</p> +<h3 id="Delete">Implementing the delete() method</h3> +<p> + The {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} method + does not have to physically delete rows from your data storage. If you are using a sync adapter + with your provider, you should consider marking a deleted row + with a "delete" flag rather than removing the row entirely. The sync adapter can + check for deleted rows and remove them from the server before deleting them from the provider. +</p> +<h3 id="Update">Implementing the update() method</h3> +<p> + The {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[]) + update()} method takes the same {@link android.content.ContentValues} argument used by + {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}, and the + same <code>selection</code> and <code>selectionArgs</code> arguments used by + {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} and + {@link android.content.ContentProvider#query(Uri, String[], String, String[], String) + ContentProvider.query()}. This may allow you to re-use code between these methods. +</p> +<h3 id="OnCreate">Implementing the onCreate() method</h3> +<p> + The Android system calls {@link android.content.ContentProvider#onCreate() + onCreate()} when it starts up the provider. You should perform only fast-running initialization + tasks in this method, and defer database creation and data loading until the provider actually + receives a request for the data. If you do lengthy tasks in + {@link android.content.ContentProvider#onCreate() onCreate()}, you will slow down your + provider's startup. In turn, this will slow down the response from the provider to other + applications. +</p> +<p> + For example, if you are using an SQLite database you can create + a new {@link android.database.sqlite.SQLiteOpenHelper} object in + {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()}, + and then create the SQL tables the first time you open the database. To facilitate this, the + first time you call {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase + getWritableDatabase()}, it automatically calls the + {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) + SQLiteOpenHelper.onCreate()} method. +</p> +<p> + The following two snippets demonstrate the interaction between + {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} and + {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) + SQLiteOpenHelper.onCreate()}. The first snippet is the implementation of + {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()}: +</p> +<pre class="prettyprint"> +public class ExampleProvider extends ContentProvider + + /* + * Defines a handle to the database helper object. The MainDatabaseHelper class is defined + * in a following snippet. + */ + private MainDatabaseHelper mOpenHelper; + + // Defines the database name + private static final String DBNAME = "mydb"; + + // Holds the database object + private SQLiteDatabase db; + + public boolean onCreate() { + + /* + * Creates a new helper object. This method always returns quickly. + * Notice that the database itself isn't created or opened + * until SQLiteOpenHelper.getWritableDatabase is called + */ + mOpenHelper = new SQLiteOpenHelper( + getContext(), // the application context + DBNAME, // the name of the database) + null, // uses the default SQLite cursor + 1 // the version number + ); + + return true; + } + + ... + + // Implements the provider's insert method + public Cursor insert(Uri uri, ContentValues values) { + // Insert code here to determine which table to open, handle error-checking, and so forth + + ... + + /* + * Gets a writeable database. This will trigger its creation if it doesn't already exist. + * + */ + db = mOpenHelper.getWritableDatabase(); + } +} +</pre> +<p> + The next snippet is the implementation of + {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) + SQLiteOpenHelper.onCreate()}, including a helper class: +</p> +<pre class="prettyprint"> +... +// A string that defines the SQL statement for creating a table +private static final String SQL_CREATE_MAIN = "CREATE TABLE " + + "main " + // Table's name + "(" + // The columns in the table + " _ID INTEGER PRIMARY KEY, " + + " WORD TEXT" + " FREQUENCY INTEGER " + + " LOCALE TEXT )"; +... +/** + * Helper class that actually creates and manages the provider's underlying data repository. + */ +protected static final class MainDatabaseHelper extends SQLiteOpenHelper { + + /* + * Instantiates an open helper for the provider's SQLite data repository + * Do not do database creation and upgrade here. + */ + MainDatabaseHelper(Context context) { + super(context, DBNAME, null, 1); + } + + /* + * Creates the data repository. This is called when the provider attempts to open the + * repository and SQLite reports that it doesn't exist. + */ + public void onCreate(SQLiteDatabase db) { + + // Creates the main table + db.execSQL(SQL_CREATE_MAIN); + } +} +</pre> + + +<!-- Implementing ContentProvider MIME Types --> +<h2 id="MIMETypes">Implementing ContentProvider MIME Types</h2> +<p> + The {@link android.content.ContentProvider} class has two methods for returning MIME types: +</p> +<dl> + <dt> + {@link android.content.ContentProvider#getType(Uri) getType()} + </dt> + <dd> + One of the required methods that you must implement for any provider. + </dd> + <dt> + {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()} + </dt> + <dd> + A method that you're expected to implement if your provider offers files. + </dd> +</dl> +<h3 id="TableMIMETypes">MIME types for tables</h3> +<p> + The {@link android.content.ContentProvider#getType(Uri) getType()} method returns a + {@link java.lang.String} in MIME format that describes the type of data returned by the content + URI argument. The {@link android.net.Uri} argument can be a pattern rather than a specific URI; + in this case, you should return the type of data associated with content URIs that match the + pattern. +</p> +<p> + For common types of data such as as text, HTML, or JPEG, + {@link android.content.ContentProvider#getType(Uri) getType()} should return the standard + MIME type for that data. A full list of these standard types is available on the + <a href="http://www.iana.org/assignments/media-types/index.htm">IANA MIME Media Types</a> + website. +</p> +<p> + For content URIs that point to a row or rows of table data, + {@link android.content.ContentProvider#getType(Uri) getType()} should return + a MIME type in Android's vendor-specific MIME format: +</p> +<ul> + <li> + Type part: <code>vnd</code> + </li> + <li> + Subtype part: + <ul> + <li> + If the URI pattern is for a single row: <code>android.cursor.<strong>item</strong>/</code> + </li> + <li> + If the URI pattern is for more than one row: <code>android.cursor.<strong>dir</strong>/</code> + </li> + </ul> + </li> + <li> + Provider-specific part: <code>vnd.<name></code>.<code><type></code> + <p> + You supply the <code><name></code> and <code><type></code>. + The <code><name></code> value should be globally unique, + and the <code><type></code> value should be unique to the corresponding URI + pattern. A good choice for <code><name></code> is your company's name or + some part of your application's Android package name. A good choice for the + <code><type></code> is a string that identifies the table associated with the + URI. + </p> + + </li> +</ul> +<p> + For example, if a provider's authority is + <code>com.example.app.provider</code>, and it exposes a table named + <code>table1</code>, the MIME type for multiple rows in <code>table1</code> is: +</p> +<pre> +vnd.android.cursor.<strong>dir</strong>/vnd.com.example.provider.table1 +</pre> +<p> + For a single row of <code>table1</code>, the MIME type is: +</p> +<pre> +vnd.android.cursor.<strong>item</strong>/vnd.com.example.provider.table1 +</pre> +<h3 id="FileMIMETypes">MIME types for files</h3> +<p> + If your provider offers files, implement + {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}. + The method returns a {@link java.lang.String} array of MIME types for the files your provider + can return for a given content URI. You should filter the MIME types you offer by the MIME type + filter argument, so that you return only those MIME types that the client wants to handle. +</p> +<p> + For example, consider a provider that offers photo images as files in <code>.jpg</code>, + <code>.png</code>, and <code>.gif</code> format. + If an application calls {@link android.content.ContentResolver#getStreamTypes(Uri, String) + ContentResolver.getStreamTypes()} with the filter string <code>image/*</code> (something that + is an "image"), + then the {@link android.content.ContentProvider#getStreamTypes(Uri, String) + ContentProvider.getStreamTypes()} method should return the array: +</p> +<pre> +{ "image/jpeg", "image/png", "image/gif"} +</pre> +<p> + If the app is only interested in <code>.jpg</code> files, then it can call + {@link android.content.ContentResolver#getStreamTypes(Uri, String) + ContentResolver.getStreamTypes()} with the filter string <code>*\/jpeg</code>, and + {@link android.content.ContentProvider#getStreamTypes(Uri, String) + ContentProvider.getStreamTypes()} should return: +<pre> +{"image/jpeg"} +</pre> +<p> + If your provider doesn't offer any of the MIME types requested in the filter string, + {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()} + should return <code>null</code>. +</p> + + +<!-- Implementing a Contract Class --> +<h2 id="ContractClass">Implementing a Contract Class</h2> +<p> + A contract class is a <code>public final</code> class that contains constant definitions for the + URIs, column names, MIME types, and other meta-data that pertain to the provider. The class + establishes a contract between the provider and other applications by ensuring that the provider + can be correctly accessed even if there are changes to the actual values of URIs, column names, + and so forth. +</p> +<p> + A contract class also helps developers because it usually has mnemonic names for its constants, + so developers are less likely to use incorrect values for column names or URIs. Since it's a + class, it can contain Javadoc documentation. Integrated development environments such as + Eclipse can auto-complete constant names from the contract class and display Javadoc for the + constants. +</p> +<p> + Developers can't access the contract class's class file from your application, but they can + statically compile it into their application from a <code>.jar</code> file you provide. +</p> +<p> + The {@link android.provider.ContactsContract} class and its nested classes are examples of + contract classes. +</p> +<h2 id="Permissions">Implementing Content Provider Permissions</h2> +<p> + Permissions and access for all aspects of the Android system are described in detail in the + topic <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>. + The topic <a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a> also + described the security and permissions in effect for various types of storage. + In brief, the important points are: +</p> +<ul> + <li> + By default, data files stored on the device's internal storage are private to your + application and provider. + </li> + <li> + {@link android.database.sqlite.SQLiteDatabase} databases you create are private to your + application and provider. + </li> + <li> + By default, data files that you save to external storage are <em>public</em> and + <em>world-readable</em>. You can't use a content provider to restrict access to files in + external storage, because other applications can use other API calls to read and write them. + </li> + <li> + The method calls for opening or creating files or SQLite databases on your device's internal + storage can potentially give both read and write access to all other applications. If you + use an internal file or database as your provider's repository, and you give it + "world-readable" or "world-writeable" access, the permissions you set for your provider in + its manifest won't protect your data. The default access for files and databases in + internal storage is "private", and for your provider's repository you shouldn't change this. + </li> +</ul> +<p> + If you want to use content provider permissions to control access to your data, then you should + store your data in internal files, SQLite databases, or the "cloud" (for example, + on a remote server), and you should keep files and databases private to your application. +</p> +<h3>Implementing permissions</h3> +<p> + All applications can read from or write to your provider, even if the underlying data is + private, because by default your provider does not have permissions set. To change this, + set permissions for your provider in your manifest file, using attributes or child + elements of the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> element. You can set permissions that apply to the entire provider, + or to certain tables, or even to certain records, or all three. +</p> +<p> + You define permissions for your provider with one or more + <code><a href="{@docRoot}guide/topics/manifest/permission-element.html"> + <permission></a></code> elements in your manifest file. To make the + permission unique to your provider, use Java-style scoping for the + <code><a href="{@docRoot}guide/topics/manifest/permission-element.html#nm"> + android:name</a></code> attribute. For example, name the read permission + <code>com.example.app.provider.permission.READ_PROVIDER</code>. + +</p> +<p> + The following list describes the scope of provider permissions, starting with the + permissions that apply to the entire provider and then becoming more fine-grained. + More fine-grained permissions take precedence over ones with larger scope: +</p> +<dl> + <dt> + Single read-write provider-level permission + </dt> + <dd> + One permission that controls both read and write access to the entire provider, specified + with the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn"> + android:permission</a></code> attribute of the + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> element. + </dd> + <dt> + Separate read and write provider-level permission + </dt> + <dd> + A read permission and a write permission for the entire provider. You specify them + with the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn"> + android:readPermission</a></code> and + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn"> + android:writePermission</a></code> attributes of the + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> element. They take precedence over the permission required by + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn"> + android:permission</a></code>. + </dd> + <dt> + Path-level permission + </dt> + <dd> + Read, write, or read/write permission for a content URI in your provider. You specify + each URI you want to control with a + <code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html"> + <path-permission></a></code> child element of the + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> element. For each content URI you specify, you can specify a + read/write permission, a read permission, or a write permission, or all three. The read and + write permissions take precedence over the read/write permission. Also, path-level + permission takes precedence over provider-level permissions. + </dd> + <dt> + Temporary permission + </dt> + <dd> + A permission level that grants temporary access to an application, even if the application + doesn't have the permissions that are normally required. The temporary + access feature reduces the number of permissions an application has to request in + its manifest. When you turn on temporary permissions, the only applications that need + "permanent" permissions for your provider are ones that continually access all + your data. + <p> + Consider the permissions you need to implement an email provider and app, when you + want to allow an outside image viewer application to display photo attachments from your + provider. To give the image viewer the necessary access without requiring permissions, + set up temporary permissions for content URIs for photos. Design your email app so + that when the user wants to display a photo, the app sends an intent containing the + photo's content URI and permission flags to the image viewer. The image viewer can + then query your email provider to retrieve the photo, even though the viewer doesn't + have the normal read permission for your provider. + </p> + <p> + To turn on temporary permissions, either set the + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn"> + android:grantUriPermissions</a></code> attribute of the + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> element, or add one or more + <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"> + <grant-uri-permission></a></code> child elements to your + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> element. If you use temporary permissions, you have to call + {@link android.content.Context#revokeUriPermission(Uri, int) + Context.revokeUriPermission()} whenever you remove support for a content URI from your + provider, and the content URI is associated with a temporary permission. + </p> + <p> + The attribute's value determines how much of your provider is made accessible. + If the attribute is set to <code>true</code>, then the system will grant temporary + permission to your entire provider, overriding any other permissions that are required + by your provider-level or path-level permissions. + </p> + <p> + If this flag is set to <code>false</code>, then you must add + <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"> + <grant-uri-permission></a></code> child elements to your + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> element. Each child element specifies the content URI or + URIs for which temporary access is granted. + </p> + <p> + To delegate temporary access to an application, an intent must contain + the {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} or the + {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} flags, or both. These + are set with the {@link android.content.Intent#setFlags(int) setFlags()} method. + </p> + <p> + If the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn"> + android:grantUriPermissions</a></code> attribute is not present, it's assumed to be + <code>false</code>. + </p> + </dd> +</dl> + + + +<!-- The Provider Element --> +<h2 id="ProviderElement">The <provider> Element</h2> +<p> + Like {@link android.app.Activity} and {@link android.app.Service} components, + a subclass of {@link android.content.ContentProvider} + must be defined in the manifest file for its application, using the + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> element. The Android system gets the following information from + the element: +<dl> + <dt> + Authority + (<a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">{@code + android:authorities}</a>) + </dt> + <dd> + Symbolic names that identify the entire provider within the system. This + attribute is described in more detail in the section + <a href="#ContentURI">Designing Content URIs</a>. + </dd> + <dt> + Provider class name + (<code> +<a href="{@docRoot}guide/topics/manifest/provider-element.html#nm">android:name</a> + </code>) + </dt> + <dd> + The class that implements {@link android.content.ContentProvider}. This class is + described in more detail in the section + <a href="#ContentProvider">Implementing the ContentProvider Class</a>. + </dd> + <dt> + Permissions + </dt> + <dd> + Attributes that specify the permissions that other applications must have in order to access + the provider's data: + <ul> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn"> + android:grantUriPermssions</a></code>: Temporary permission flag. + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn"> + android:permission</a></code>: Single provider-wide read/write permission. + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn"> + android:readPermission</a></code>: Provider-wide read permission. + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn"> + android:writePermission</a></code>: Provider-wide write permission. + </li> + </ul> + <p> + Permissions and their corresponding attributes are described in more + detail in the section + <a href="#Permissions">Implementing Content Provider Permissions</a>. + </p> + </dd> + <dt> + Startup and control attributes + </dt> + <dd> + These attributes determine how and when the Android system starts the provider, the + process characteristics of the provider, and other run-time settings: + <ul> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#enabled"> + android:enabled</a></code>: Flag allowing the system to start the provider. + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#exported"> + android:exported</a></code>: Flag allowing other applications to use this provider. + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#init"> + android:initOrder</a></code>: The order in which this provider should be started, + relative to other providers in the same process. + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#multi"> + android:multiProcess</a></code>: Flag allowing the system to start the provider + in the same process as the calling client. + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#proc"> + android:process</a></code>: The name of the process in which the provider should + run. + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#sync"> + android:syncable</a></code>: Flag indicating that the provider's data is to be + sync'ed with data on a server. + </li> + </ul> + <p> + The attributes are fully documented in the dev guide topic for the + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> + element. + </p> + </dd> + <dt> + Informational attributes + </dt> + <dd> + An optional icon and label for the provider: + <ul> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#icon"> + android:icon</a></code>: A drawable resource containing an icon for the provider. + The icon appears next to the provider's label in the list of apps in + <em>Settings</em> > <em>Apps</em> > <em>All</em>. + </li> + <li> + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#label"> + android:label</a></code>: An informational label describing the provider or its + data, or both. The label appears in the list of apps in + <em>Settings</em> > <em>Apps</em> > <em>All</em>. + </li> + </ul> + <p> + The attributes are fully documented in the dev guide topic for the + <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> + <provider></a></code> element. + </p> + </dd> +</dl> + +<!-- Intent Access --> +<h2 id="Intents">Intents and Data Access</h2> +<p> + Applications can access a content provider indirectly with an {@link android.content.Intent}. + The application does not call any of the methods of {@link android.content.ContentResolver} or + {@link android.content.ContentProvider}. Instead, it sends an intent that starts an activity, + which is often part of the provider's own application. The destination activity is in charge of + retrieving and displaying the data in its UI. Depending on the action in the intent, the + destination activity may also prompt the user to make modifications to the provider's data. + An intent may also contain "extras" data that the destination activity displays + in the UI; the user then has the option of changing this data before using it to modify the + data in the provider. +</p> +<p> + +</p> +<p> + You may want to use intent access to help ensure data integrity. Your provider may depend + on having data inserted, updated, and deleted according to strictly defined business logic. If + this is the case, allowing other applications to directly modify your data may lead to + invalid data. If you want developers to use intent access, be sure to document it thoroughly. + Explain to them why intent access using your own application's UI is better than trying to + modify the data with their code. +</p> +<p> + Handling an incoming intent that wishes to modify your provider's data is no different from + handling other intents. You can learn more about using intents by reading the topic + <a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a>. +</p> diff --git a/docs/html/guide/topics/providers/content-providers.jd b/docs/html/guide/topics/providers/content-providers.jd index 95331ce..1707f03 100644 --- a/docs/html/guide/topics/providers/content-providers.jd +++ b/docs/html/guide/topics/providers/content-providers.jd @@ -1,922 +1,96 @@ page.title=Content Providers @jd:body - <div id="qv-wrapper"> <div id="qv"> -<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> -<h2>Key classes</h2> +<!-- In this document --> +<h2>Topics</h2> <ol> -<li>{@link android.content.ContentProvider}</li> -<li>{@link android.content.ContentResolver}</li> -<li>{@link android.database.Cursor}</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>See also</h2> -<ol> - <li><a href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar Provider</a></li> -</ol> + <!-- Related Samples --> +<h2>Related Samples</h2> + <ol> + <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. -</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 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. -</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> -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> - - + 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> + 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> + 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> + 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> +<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> |