Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 1 | page.title=Content Provider Basics |
| 2 | @jd:body |
| 3 | <div id="qv-wrapper"> |
| 4 | <div id="qv"> |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 5 | <!-- In this document --> |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 6 | <h2>In this document</h2> |
| 7 | <ol> |
| 8 | <li> |
| 9 | <a href="#Basics">Overview</a> |
| 10 | <ol> |
| 11 | <li> |
| 12 | <a href="#ClientProvider">Accessing a provider</a> |
| 13 | </li> |
| 14 | <li> |
| 15 | <a href="#ContentURIs">Content URIs</a> |
| 16 | </li> |
| 17 | </ol> |
| 18 | </li> |
| 19 | <li> |
| 20 | <a href="#SimpleQuery">Retrieving Data from the Provider</a> |
| 21 | <ol> |
| 22 | <li> |
| 23 | <a href="#RequestPermissions">Requesting read access permission</a> |
| 24 | </li> |
| 25 | <li> |
| 26 | <a href="#Query">Constructing the query</a> |
| 27 | </li> |
| 28 | <li> |
| 29 | <a href="#DisplayResults">Displaying query results</a> |
| 30 | </li> |
| 31 | <li> |
| 32 | <a href="#GettingResults">Getting data from query results</a> |
| 33 | </li> |
| 34 | </ol> |
| 35 | </li> |
| 36 | <li> |
| 37 | <a href="#Permissions">Content Provider Permissions</a> |
| 38 | </li> |
| 39 | <li> |
| 40 | <a href="#Modifications">Inserting, Updating, and Deleting Data</a> |
| 41 | <ol> |
| 42 | <li> |
| 43 | <a href="#Inserting">Inserting data</a> |
| 44 | </li> |
| 45 | <li> |
| 46 | <a href="#Updating">Updating data</a> |
| 47 | </li> |
| 48 | <li> |
| 49 | <a href="#Deleting">Deleting data</a> |
| 50 | </li> |
| 51 | </ol> |
| 52 | </li> |
| 53 | <li> |
| 54 | <a href="#DataTypes">Provider Data Types</a> |
| 55 | </li> |
| 56 | <li> |
| 57 | <a href="#AltForms">Alternative Forms of Provider Access</a> |
| 58 | <ol> |
| 59 | <li> |
| 60 | <a href="#Batch">Batch access</a> |
| 61 | </li> |
| 62 | <li> |
| 63 | <a href="#Intents">Data access via intents</a> |
| 64 | </li> |
| 65 | </ol> |
| 66 | </li> |
| 67 | <li> |
| 68 | <a href="#ContractClasses">Contract Classes</a> |
| 69 | </li> |
| 70 | <li> |
| 71 | <a href="#MIMETypeReference">MIME Type Reference</a> |
| 72 | </li> |
| 73 | </ol> |
| 74 | |
| 75 | <!-- Key Classes --> |
| 76 | <h2>Key classes</h2> |
| 77 | <ol> |
| 78 | <li> |
| 79 | {@link android.content.ContentProvider} |
| 80 | </li> |
| 81 | <li> |
| 82 | {@link android.content.ContentResolver} |
| 83 | </li> |
| 84 | <li> |
| 85 | {@link android.database.Cursor} |
| 86 | </li> |
| 87 | <li> |
| 88 | {@link android.net.Uri} |
| 89 | </li> |
| 90 | </ol> |
| 91 | |
| 92 | <!-- Related Samples --> |
| 93 | <h2>Related Samples</h2> |
| 94 | <ol> |
| 95 | <li> |
| 96 | <a |
| 97 | href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html"> |
| 98 | Cursor (People)</a> |
| 99 | </li> |
| 100 | <li> |
| 101 | <a |
| 102 | href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html"> |
| 103 | Cursor (Phones)</a> |
| 104 | </li> |
| 105 | </ol> |
| 106 | |
| 107 | <!-- See also --> |
| 108 | <h2>See also</h2> |
| 109 | <ol> |
| 110 | <li> |
| 111 | <a href="{@docRoot}guide/topics/providers/content-provider-creating.html"> |
| 112 | Creating a Content Provider</a> |
| 113 | </li> |
| 114 | <li> |
| 115 | <a href="{@docRoot}guide/topics/providers/calendar-provider.html"> |
| 116 | Calendar Provider</a> |
| 117 | </li> |
| 118 | </ol> |
| 119 | </div> |
| 120 | </div> |
| 121 | |
| 122 | <!-- Intro paragraphs --> |
| 123 | <p> |
Scott Main | 8edad6f | 2012-03-09 10:55:50 -0800 | [diff] [blame] | 124 | A content provider manages access to a central repository of data. A provider |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 125 | is part of an Android application, which often provides its own UI for working with |
| 126 | the data. However, content providers are primarily intended to be used by other |
| 127 | applications, which access the provider using a provider client object. Together, providers |
| 128 | and provider clients offer a consistent, standard interface to data that also handles |
| 129 | inter-process communication and secure data access. |
| 130 | </p> |
| 131 | <p> |
| 132 | This topic describes the basics of the following: |
| 133 | </p> |
| 134 | <ul> |
| 135 | <li>How content providers work.</li> |
| 136 | <li>The API you use retrieve data from a content provider.</li> |
| 137 | <li>The API you use to insert, update, or delete data in a content provider.</li> |
| 138 | <li>Other API features that facilitate working with providers.</li> |
| 139 | </ul> |
| 140 | |
| 141 | <!-- Basics --> |
| 142 | <h2 id="Basics">Overview</h2> |
| 143 | <p> |
| 144 | A content provider presents data to external applications as one or more tables that are |
| 145 | similar to the tables found in a relational database. A row represents an instance of some type |
Joe Malin | 5d64aa2 | 2013-02-28 09:18:24 -0800 | [diff] [blame] | 146 | of data the provider collects, and each column in the row represents an individual piece of |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 147 | data collected for an instance. |
| 148 | </p> |
| 149 | <p> |
| 150 | For example, one of the built-in providers in the Android platform is the user dictionary, which |
| 151 | stores the spellings of non-standard words that the user wants to keep. Table 1 illustrates what |
| 152 | the data might look like in this provider's table: |
| 153 | </p> |
| 154 | <p class="table-caption"> |
| 155 | <strong>Table 1:</strong> Sample user dictionary table. |
| 156 | </p> |
| 157 | <table id="table1" style="width: 50%;"> |
| 158 | <tr> |
| 159 | <th style="width:20%" align="center" scope="col">word</th> |
| 160 | <th style="width:20%" align="center" scope="col">app id</th> |
| 161 | <th style="width:20%" align="center" scope="col">frequency</th> |
| 162 | <th style="width:20%" align="center" scope="col">locale</th> |
| 163 | <th style="width:20%" align="center" scope="col">_ID</th> |
| 164 | </tr> |
| 165 | <tr> |
| 166 | <td align="center" scope="row">mapreduce</td> |
| 167 | <td align="center">user1</td> |
| 168 | <td align="center">100</td> |
| 169 | <td align="center">en_US</td> |
| 170 | <td align="center">1</td> |
| 171 | </tr> |
| 172 | <tr> |
| 173 | <td align="center" scope="row">precompiler</td> |
| 174 | <td align="center">user14</td> |
| 175 | <td align="center">200</td> |
| 176 | <td align="center">fr_FR</td> |
| 177 | <td align="center">2</td> |
| 178 | </tr> |
| 179 | <tr> |
| 180 | <td align="center" scope="row">applet</td> |
| 181 | <td align="center">user2</td> |
| 182 | <td align="center">225</td> |
| 183 | <td align="center">fr_CA</td> |
| 184 | <td align="center">3</td> |
| 185 | </tr> |
| 186 | <tr> |
| 187 | <td align="center" scope="row">const</td> |
| 188 | <td align="center">user1</td> |
| 189 | <td align="center">255</td> |
| 190 | <td align="center">pt_BR</td> |
| 191 | <td align="center">4</td> |
| 192 | </tr> |
| 193 | <tr> |
| 194 | <td align="center" scope="row">int</td> |
| 195 | <td align="center">user5</td> |
| 196 | <td align="center">100</td> |
| 197 | <td align="center">en_UK</td> |
| 198 | <td align="center">5</td> |
| 199 | </tr> |
| 200 | </table> |
| 201 | <p> |
| 202 | In table 1, each row represents an instance of a word that might not be |
| 203 | found in a standard dictionary. Each column represents some data for that word, such as the |
| 204 | locale in which it was first encountered. The column headers are column names that are stored in |
| 205 | the provider. To refer to a row's locale, you refer to its <code>locale</code> column. For |
| 206 | this provider, the <code>_ID</code> column serves as a "primary key" column that |
| 207 | the provider automatically maintains. |
| 208 | </p> |
| 209 | <p class="note"> |
| 210 | <strong>Note:</strong> A provider isn't required to have a primary key, and it isn't required |
| 211 | to use <code>_ID</code> as the column name of a primary key if one is present. However, |
| 212 | if you want to bind data from a provider to a {@link android.widget.ListView}, one of the |
| 213 | column names has to be <code>_ID</code>. This requirement is explained in more detail in the |
| 214 | section <a href="#DisplayResults">Displaying query results</a>. |
| 215 | </p> |
| 216 | <h3 id="ClientProvider">Accessing a provider</h3> |
| 217 | <p> |
| 218 | An application accesses the data from a content provider with |
| 219 | a {@link android.content.ContentResolver} client object. This object has methods that call |
| 220 | identically-named methods in the provider object, an instance of one of the concrete |
| 221 | subclasses of {@link android.content.ContentProvider}. The |
| 222 | {@link android.content.ContentResolver} methods provide the basic |
| 223 | "CRUD" (create, retrieve, update, and delete) functions of persistent storage. |
| 224 | </p> |
| 225 | <p> |
| 226 | The {@link android.content.ContentResolver} object in the client application's |
| 227 | process and the {@link android.content.ContentProvider} object in the application that owns |
| 228 | the provider automatically handle inter-process communication. |
| 229 | {@link android.content.ContentProvider} also acts as an abstraction layer between its |
| 230 | repository of data and the external appearance of data as tables. |
| 231 | </p> |
| 232 | <p class="note"> |
| 233 | <strong>Note:</strong> To access a provider, your application usually has to request specific |
| 234 | permissions in its manifest file. This is described in more detail in the section |
| 235 | <a href="#Permissions">Content Provider Permissions</a> |
| 236 | </p> |
| 237 | <p> |
| 238 | For example, to get a list of the words and their locales from the User Dictionary Provider, |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 239 | you call {@link android.content.ContentResolver#query ContentResolver.query()}. |
| 240 | The {@link android.content.ContentResolver#query query()} method calls the |
| 241 | {@link android.content.ContentProvider#query ContentProvider.query()} method defined by the |
| 242 | User Dictionary Provider. The following lines of code show a |
| 243 | {@link android.content.ContentResolver#query ContentResolver.query()} call: |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 244 | <p> |
| 245 | <pre> |
| 246 | // Queries the user dictionary and returns results |
| 247 | mCursor = getContentResolver().query( |
| 248 | UserDictionary.Words.CONTENT_URI, // The content URI of the words table |
| 249 | mProjection, // The columns to return for each row |
| 250 | mSelectionClause // Selection criteria |
| 251 | mSelectionArgs, // Selection criteria |
| 252 | mSortOrder); // The sort order for the returned rows |
| 253 | </pre> |
| 254 | <p> |
| 255 | Table 2 shows how the arguments to |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 256 | {@link android.content.ContentResolver#query |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 257 | query(Uri,projection,selection,selectionArgs,sortOrder)} match an SQL SELECT statement: |
| 258 | </p> |
| 259 | <p class="table-caption"> |
| 260 | <strong>Table 2:</strong> Query() compared to SQL query. |
| 261 | </p> |
| 262 | <table id="table2" style="width: 75%;"> |
| 263 | <tr> |
| 264 | <th style="width:25%" align="center" scope="col">query() argument</th> |
| 265 | <th style="width:25%" align="center" scope="col">SELECT keyword/parameter</th> |
| 266 | <th style="width:50%" align="center" scope="col">Notes</th> |
| 267 | </tr> |
| 268 | <tr> |
| 269 | <td align="center"><code>Uri</code></td> |
| 270 | <td align="center"><code>FROM <em>table_name</em></code></td> |
| 271 | <td><code>Uri</code> maps to the table in the provider named <em>table_name</em>.</td> |
| 272 | </tr> |
| 273 | <tr> |
| 274 | <td align="center"><code>projection</code></td> |
| 275 | <td align="center"><code><em>col,col,col,...</em></code></td> |
| 276 | <td> |
| 277 | <code>projection</code> is an array of columns that should be included for each row |
| 278 | retrieved. |
| 279 | </td> |
| 280 | </tr> |
| 281 | <tr> |
| 282 | <td align="center"><code>selection</code></td> |
| 283 | <td align="center"><code>WHERE <em>col</em> = <em>value</em></code></td> |
| 284 | <td><code>selection</code> specifies the criteria for selecting rows.</td> |
| 285 | </tr> |
| 286 | <tr> |
| 287 | <td align="center"><code>selectionArgs</code></td> |
| 288 | <td align="center"> |
| 289 | (No exact equivalent. Selection arguments replace <code>?</code> placeholders in the |
| 290 | selection clause.) |
| 291 | </td> |
| 292 | </tr> |
| 293 | <tr> |
| 294 | <td align="center"><code>sortOrder</code></td> |
| 295 | <td align="center"><code>ORDER BY <em>col,col,...</em></code></td> |
| 296 | <td> |
| 297 | <code>sortOrder</code> specifies the order in which rows appear in the returned |
| 298 | {@link android.database.Cursor}. |
| 299 | </td> |
| 300 | </tr> |
| 301 | </table> |
| 302 | <h3 id="ContentURIs">Content URIs</h3> |
| 303 | <p> |
| 304 | A <strong>content URI</strong> is a URI that identifies data in a provider. Content URIs |
| 305 | include the symbolic name of the entire provider (its <strong>authority</strong>) and a |
| 306 | name that points to a table (a <strong>path</strong>). When you call |
| 307 | a client method to access a table in a provider, the content URI for the table is one of |
| 308 | the arguments. |
| 309 | </p> |
| 310 | <p> |
| 311 | In the preceding lines of code, the constant |
| 312 | {@link android.provider.UserDictionary.Words#CONTENT_URI} contains the content URI of |
| 313 | the user dictionary's "words" table. The {@link android.content.ContentResolver} |
| 314 | object parses out the URI's authority, and uses it to "resolve" the provider by |
| 315 | comparing the authority to a system table of known providers. The |
| 316 | {@link android.content.ContentResolver} can then dispatch the query arguments to the correct |
| 317 | provider. |
| 318 | </p> |
| 319 | <p> |
| 320 | The {@link android.content.ContentProvider} uses the path part of the content URI to choose the |
| 321 | table to access. A provider usually has a <strong>path</strong> for each table it exposes. |
| 322 | </p> |
| 323 | <p> |
| 324 | In the previous lines of code, the full URI for the "words" table is: |
| 325 | </p> |
| 326 | <pre> |
| 327 | content://user_dictionary/words |
| 328 | </pre> |
| 329 | <p> |
| 330 | where the <code>user_dictionary</code> string is the provider's authority, and |
| 331 | <code>words</code> string is the table's path. The string |
| 332 | <code>content://</code> (the <strong>scheme</strong>) is always present, |
| 333 | and identifies this as a content URI. |
| 334 | </p> |
| 335 | <p> |
| 336 | Many providers allow you to access a single row in a table by appending an ID value |
| 337 | to the end of the URI. For example, to retrieve a row whose <code>_ID</code> is |
| 338 | <code>4</code> from user dictionary, you can use this content URI: |
| 339 | </p> |
| 340 | <pre> |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 341 | Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4); |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 342 | </pre> |
| 343 | <p> |
| 344 | You often use id values when you've retrieved a set of rows and then want to update or delete |
| 345 | one of them. |
| 346 | </p> |
| 347 | <p class="note"> |
| 348 | <strong>Note:</strong> The {@link android.net.Uri} and {@link android.net.Uri.Builder} classes |
| 349 | contain convenience methods for constructing well-formed Uri objects from strings. The |
| 350 | {@link android.content.ContentUris} contains convenience methods for appending id values to |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 351 | a URI. The previous snippet uses {@link android.content.ContentUris#withAppendedId |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 352 | withAppendedId()} to append an id to the UserDictionary content URI. |
| 353 | </p> |
| 354 | |
| 355 | |
| 356 | <!-- Retrieving Data from the Provider --> |
| 357 | <h2 id="SimpleQuery">Retrieving Data from the Provider</h2> |
| 358 | <p> |
| 359 | This section describes how to retrieve data from a provider, using the User Dictionary Provider |
| 360 | as an example. |
| 361 | </p> |
| 362 | <p class="note"> |
| 363 | For the sake of clarity, the code snippets in this section call |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 364 | {@link android.content.ContentResolver#query ContentResolver.query()} on the "UI thread"". In |
| 365 | actual code, however, you should do queries asynchronously on a separate thread. One way to do |
| 366 | this is to use the {@link android.content.CursorLoader} class, which is described |
Scott Main | 50e990c | 2012-06-21 17:14:39 -0700 | [diff] [blame] | 367 | in more detail in the <a href="{@docRoot}guide/components/loaders.html"> |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 368 | Loaders</a> guide. Also, the lines of code are snippets only; they don't show a complete |
| 369 | application. |
| 370 | </p> |
| 371 | <p> |
| 372 | To retrieve data from a provider, follow these basic steps: |
| 373 | </p> |
| 374 | <ol> |
| 375 | <li> |
| 376 | Request the read access permission for the provider. |
| 377 | </li> |
| 378 | <li> |
| 379 | Define the code that sends a query to the provider. |
| 380 | </li> |
| 381 | </ol> |
| 382 | <h3 id="RequestPermissions">Requesting read access permission</h3> |
| 383 | <p> |
| 384 | To retrieve data from a provider, your application needs "read access permission" for the |
| 385 | provider. You can't request this permission at run-time; instead, you have to specify that |
| 386 | you need this permission in your manifest, using the |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 387 | <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> |
| 388 | element and the exact permission name defined by the |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 389 | provider. When you specify this element in your manifest, you are in effect "requesting" this |
| 390 | permission for your application. When users install your application, they implicitly grant |
| 391 | this request. |
| 392 | </p> |
| 393 | <p> |
| 394 | To find the exact name of the read access permission for the provider you're using, as well |
| 395 | as the names for other access permissions used by the provider, look in the provider's |
| 396 | documentation. |
| 397 | </p> |
| 398 | <p> |
| 399 | The role of permissions in accessing providers is described in more detail in the section |
| 400 | <a href="#Permissions">Content Provider Permissions</a>. |
| 401 | </p> |
| 402 | <p> |
| 403 | The User Dictionary Provider defines the permission |
| 404 | <code>android.permission.READ_USER_DICTIONARY</code> in its manifest file, so an |
| 405 | application that wants to read from the provider must request this permission. |
| 406 | </p> |
| 407 | <!-- Constructing the query --> |
| 408 | <h3 id="Query">Constructing the query</h3> |
| 409 | <p> |
| 410 | The next step in retrieving data a provider is to construct a query. This first snippet |
| 411 | defines some variables for accessing the User Dictionary Provider: |
| 412 | </p> |
| 413 | <pre class="prettyprint"> |
| 414 | |
| 415 | // A "projection" defines the columns that will be returned for each row |
| 416 | String[] mProjection = |
| 417 | { |
| 418 | UserDictionary.Words._ID, // Contract class constant for the _ID column name |
| 419 | UserDictionary.Words.WORD, // Contract class constant for the word column name |
| 420 | UserDictionary.Words.LOCALE // Contract class constant for the locale column name |
| 421 | }; |
| 422 | |
| 423 | // Defines a string to contain the selection clause |
| 424 | String mSelectionClause = null; |
| 425 | |
| 426 | // Initializes an array to contain selection arguments |
| 427 | String[] mSelectionArgs = {""}; |
| 428 | |
| 429 | </pre> |
| 430 | <p> |
| 431 | The next snippet shows how to use |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 432 | {@link android.content.ContentResolver#query ContentResolver.query()}, using the User Dictionary |
| 433 | Provider as an example. A provider client query is similar to an SQL query, and it contains a |
| 434 | set of columns to return, a set of selection criteria, and a sort order. |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 435 | </p> |
| 436 | <p> |
| 437 | The set of columns that the query should return is called a <strong>projection</strong> |
| 438 | (the variable <code>mProjection</code>). |
| 439 | </p> |
| 440 | <p> |
| 441 | The expression that specifies the rows to retrieve is split into a selection clause and |
| 442 | selection arguments. The selection clause is a combination of logical and Boolean expressions, |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 443 | column names, and values (the variable <code>mSelectionClause</code>). If you specify the |
| 444 | replaceable parameter <code>?</code> instead of a value, the query method retrieves the value |
| 445 | from the selection arguments array (the variable <code>mSelectionArgs</code>). |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 446 | </p> |
| 447 | <p> |
| 448 | In the next snippet, if the user doesn't enter a word, the selection clause is set to |
| 449 | <code>null</code>, and the query returns all the words in the provider. If the user enters |
Joe Malin | fd29e8a | 2012-07-03 14:19:20 -0700 | [diff] [blame] | 450 | a word, the selection clause is set to <code>UserDictionary.Words.WORD + " = ?"</code> and |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 451 | the first element of selection arguments array is set to the word the user enters. |
| 452 | </p> |
| 453 | <pre class="prettyprint"> |
| 454 | /* |
| 455 | * This defines a one-element String array to contain the selection argument. |
| 456 | */ |
| 457 | String[] mSelectionArgs = {""}; |
| 458 | |
| 459 | // Gets a word from the UI |
| 460 | mSearchString = mSearchWord.getText().toString(); |
| 461 | |
| 462 | // Remember to insert code here to check for invalid or malicious input. |
| 463 | |
| 464 | // If the word is the empty string, gets everything |
| 465 | if (TextUtils.isEmpty(mSearchString)) { |
| 466 | // Setting the selection clause to null will return all words |
| 467 | mSelectionClause = null; |
| 468 | mSelectionArgs[0] = ""; |
| 469 | |
| 470 | } else { |
| 471 | // Constructs a selection clause that matches the word that the user entered. |
Joe Malin | fd29e8a | 2012-07-03 14:19:20 -0700 | [diff] [blame] | 472 | mSelectionClause = UserDictionary.Words.WORD + " = ?"; |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 473 | |
| 474 | // Moves the user's input string to the selection arguments. |
| 475 | mSelectionArgs[0] = mSearchString; |
| 476 | |
| 477 | } |
| 478 | |
| 479 | // Does a query against the table and returns a Cursor object |
| 480 | mCursor = getContentResolver().query( |
| 481 | UserDictionary.Words.CONTENT_URI, // The content URI of the words table |
| 482 | mProjection, // The columns to return for each row |
| 483 | mSelectionClause // Either null, or the word the user entered |
| 484 | mSelectionArgs, // Either empty, or the string the user entered |
| 485 | mSortOrder); // The sort order for the returned rows |
| 486 | |
| 487 | // Some providers return null if an error occurs, others throw an exception |
| 488 | if (null == mCursor) { |
| 489 | /* |
| 490 | * Insert code here to handle the error. Be sure not to use the cursor! You may want to |
| 491 | * call android.util.Log.e() to log this error. |
| 492 | * |
| 493 | */ |
| 494 | // If the Cursor is empty, the provider found no matches |
| 495 | } else if (mCursor.getCount() < 1) { |
| 496 | |
| 497 | /* |
| 498 | * Insert code here to notify the user that the search was unsuccessful. This isn't necessarily |
| 499 | * an error. You may want to offer the user the option to insert a new row, or re-type the |
| 500 | * search term. |
| 501 | */ |
| 502 | |
| 503 | } else { |
| 504 | // Insert code here to do something with the results |
| 505 | |
| 506 | } |
| 507 | </pre> |
| 508 | <p> |
| 509 | This query is analogous to the SQL statement: |
| 510 | </p> |
| 511 | <pre> |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 512 | SELECT _ID, word, locale FROM words WHERE word = <userinput> ORDER BY word ASC; |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 513 | </pre> |
| 514 | <p> |
| 515 | In this SQL statement, the actual column names are used instead of contract class constants. |
| 516 | </p> |
| 517 | <h4 id="Injection">Protecting against malicious input</h4> |
| 518 | <p> |
| 519 | If the data managed by the content provider is in an SQL database, including external untrusted |
| 520 | data into raw SQL statements can lead to SQL injection. |
| 521 | </p> |
| 522 | <p> |
| 523 | Consider this selection clause: |
| 524 | </p> |
| 525 | <pre> |
| 526 | // Constructs a selection clause by concatenating the user's input to the column name |
| 527 | String mSelectionClause = "var = " + mUserInput; |
| 528 | </pre> |
| 529 | <p> |
| 530 | If you do this, you're allowing the user to concatenate malicious SQL onto your SQL statement. |
| 531 | For example, the user could enter "nothing; DROP TABLE *;" for <code>mUserInput</code>, which |
| 532 | would result in the selection clause <code>var = nothing; DROP TABLE *;</code>. Since the |
| 533 | selection clause is treated as an SQL statement, this might cause the provider to erase all of |
| 534 | the tables in the underlying SQLite database (unless the provider is set up to catch |
| 535 | <a href="http://en.wikipedia.org/wiki/SQL_injection">SQL injection</a> attempts). |
| 536 | </p> |
| 537 | <p> |
| 538 | To avoid this problem, use a selection clause that uses <code>?</code> as a replaceable |
| 539 | parameter and a separate array of selection arguments. When you do this, the user input |
| 540 | is bound directly to the query rather than being interpreted as part of an SQL statement. |
| 541 | Because it's not treated as SQL, the user input can't inject malicious SQL. Instead of using |
| 542 | concatenation to include the user input, use this selection clause: |
| 543 | </p> |
| 544 | <pre> |
| 545 | // Constructs a selection clause with a replaceable parameter |
| 546 | String mSelectionClause = "var = ?"; |
| 547 | </pre> |
| 548 | <p> |
| 549 | Set up the array of selection arguments like this: |
| 550 | </p> |
| 551 | <pre> |
| 552 | // Defines an array to contain the selection arguments |
| 553 | String[] selectionArgs = {""}; |
| 554 | </pre> |
| 555 | <p> |
| 556 | Put a value in the selection arguments array like this: |
| 557 | </p> |
| 558 | <pre> |
| 559 | // Sets the selection argument to the user's input |
| 560 | selectionArgs[0] = mUserInput; |
| 561 | </pre> |
| 562 | <p> |
| 563 | A selection clause that uses <code>?</code> as a replaceable parameter and an array of |
Scott Main | 8edad6f | 2012-03-09 10:55:50 -0800 | [diff] [blame] | 564 | selection arguments array are preferred way to specify a selection, even if the provider isn't |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 565 | based on an SQL database. |
| 566 | </p> |
| 567 | <!-- Displaying the results --> |
| 568 | <h3 id="DisplayResults">Displaying query results</h3> |
| 569 | <p> |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 570 | The {@link android.content.ContentResolver#query ContentResolver.query()} client method always |
| 571 | returns a {@link android.database.Cursor} containing the columns specified by the query's |
| 572 | projection for the rows that match the query's selection criteria. A |
| 573 | {@link android.database.Cursor} object provides random read access to the rows and columns it |
| 574 | contains. Using {@link android.database.Cursor} methods, you can iterate over the rows in the |
| 575 | results, determine the data type of each column, get the data out of a column, and examine other |
| 576 | properties of the results. Some {@link android.database.Cursor} implementations automatically |
| 577 | update the object when the provider's data changes, or trigger methods in an observer object |
| 578 | when the {@link android.database.Cursor} changes, or both. |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 579 | </p> |
| 580 | <p class="note"> |
| 581 | <strong>Note:</strong> A provider may restrict access to columns based on the nature of the |
| 582 | object making the query. For example, the Contacts Provider restricts access for some columns to |
| 583 | sync adapters, so it won't return them to an activity or service. |
| 584 | </p> |
| 585 | <p> |
| 586 | If no rows match the selection criteria, the provider |
| 587 | returns a {@link android.database.Cursor} object for which |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 588 | {@link android.database.Cursor#getCount Cursor.getCount()} is 0 (an empty cursor). |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 589 | </p> |
| 590 | <p> |
| 591 | If an internal error occurs, the results of the query depend on the particular provider. It may |
| 592 | choose to return <code>null</code>, or it may throw an {@link java.lang.Exception}. |
| 593 | </p> |
| 594 | <p> |
| 595 | Since a {@link android.database.Cursor} is a "list" of rows, a good way to display the |
| 596 | contents of a {@link android.database.Cursor} is to link it to a {@link android.widget.ListView} |
| 597 | via a {@link android.widget.SimpleCursorAdapter}. |
| 598 | </p> |
| 599 | <p> |
| 600 | The following snippet continues the code from the previous snippet. It creates a |
| 601 | {@link android.widget.SimpleCursorAdapter} object containing the {@link android.database.Cursor} |
| 602 | retrieved by the query, and sets this object to be the adapter for a |
| 603 | {@link android.widget.ListView}: |
| 604 | </p> |
| 605 | <pre class="prettyprint"> |
| 606 | // Defines a list of columns to retrieve from the Cursor and load into an output row |
| 607 | String[] mWordListColumns = |
| 608 | { |
| 609 | UserDictionary.Words.WORD, // Contract class constant containing the word column name |
| 610 | UserDictionary.Words.LOCALE // Contract class constant containing the locale column name |
| 611 | }; |
| 612 | |
| 613 | // Defines a list of View IDs that will receive the Cursor columns for each row |
| 614 | int[] mWordListItems = { R.id.dictWord, R.id.locale}; |
| 615 | |
| 616 | // Creates a new SimpleCursorAdapter |
| 617 | mCursorAdapter = new SimpleCursorAdapter( |
| 618 | getApplicationContext(), // The application's Context object |
| 619 | R.layout.wordlistrow, // A layout in XML for one row in the ListView |
| 620 | mCursor, // The result from the query |
| 621 | mWordListColumns, // A string array of column names in the cursor |
| 622 | mWordListItems, // An integer array of view IDs in the row layout |
| 623 | 0); // Flags (usually none are needed) |
| 624 | |
| 625 | // Sets the adapter for the ListView |
| 626 | mWordList.setAdapter(mCursorAdapter); |
| 627 | </pre> |
| 628 | <p class="note"> |
| 629 | <strong>Note:</strong> To back a {@link android.widget.ListView} with a |
| 630 | {@link android.database.Cursor}, the cursor must contain a column named <code>_ID</code>. |
| 631 | Because of this, the query shown previously retrieves the <code>_ID</code> column for the |
| 632 | "words" table, even though the {@link android.widget.ListView} doesn't display it. |
| 633 | This restriction also explains why most providers have a <code>_ID</code> column for each of |
| 634 | their tables. |
| 635 | </p> |
| 636 | |
| 637 | <!-- Getting data from query results --> |
| 638 | <h3 id="GettingResults">Getting data from query results</h3> |
| 639 | <p> |
| 640 | Rather than simply displaying query results, you can use them for other tasks. For |
| 641 | example, you can retrieve spellings from the user dictionary and then look them up in |
| 642 | other providers. To do this, you iterate over the rows in the {@link android.database.Cursor}: |
| 643 | </p> |
| 644 | <pre class="prettyprint"> |
| 645 | |
| 646 | // Determine the column index of the column named "word" |
| 647 | int index = mCursor.getColumnIndex(UserDictionary.Words.WORD); |
| 648 | |
| 649 | /* |
| 650 | * Only executes if the cursor is valid. The User Dictionary Provider returns null if |
| 651 | * an internal error occurs. Other providers may throw an Exception instead of returning null. |
| 652 | */ |
| 653 | |
| 654 | if (mCursor != null) { |
| 655 | /* |
| 656 | * Moves to the next row in the cursor. Before the first movement in the cursor, the |
| 657 | * "row pointer" is -1, and if you try to retrieve data at that position you will get an |
| 658 | * exception. |
| 659 | */ |
| 660 | while (mCursor.moveToNext()) { |
| 661 | |
| 662 | // Gets the value from the column. |
| 663 | newWord = mCursor.getString(index); |
| 664 | |
| 665 | // Insert code here to process the retrieved word. |
| 666 | |
| 667 | ... |
| 668 | |
| 669 | // end of while loop |
| 670 | } |
| 671 | } else { |
| 672 | |
| 673 | // Insert code here to report an error if the cursor is null or the provider threw an exception. |
| 674 | } |
| 675 | </pre> |
| 676 | <p> |
| 677 | {@link android.database.Cursor} implementations contain several "get" methods for |
| 678 | retrieving different types of data from the object. For example, the previous snippet |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 679 | uses {@link android.database.Cursor#getString getString()}. They also have a |
| 680 | {@link android.database.Cursor#getType getType()} method that returns a value indicating |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 681 | the data type of the column. |
| 682 | </p> |
| 683 | |
| 684 | |
| 685 | <!-- Requesting permissions --> |
| 686 | <h2 id="Permissions">Content Provider Permissions</h2> |
| 687 | <p> |
| 688 | A provider's application can specify permissions that other applications must have in order to |
| 689 | access the provider's data. These permissions ensure that the user knows what data |
| 690 | an application will try to access. Based on the provider's requirements, other applications |
| 691 | request the permissions they need in order to access the provider. End users see the requested |
| 692 | permissions when they install the application. |
| 693 | </p> |
| 694 | <p> |
| 695 | If a provider's application doesn't specify any permissions, then other applications have no |
| 696 | access to the provider's data. However, components in the provider's application always have |
| 697 | full read and write access, regardless of the specified permissions. |
| 698 | </p> |
| 699 | <p> |
| 700 | As noted previously, the User Dictionary Provider requires the |
| 701 | <code>android.permission.READ_USER_DICTIONARY</code> permission to retrieve data from it. |
| 702 | The provider has the separate <code>android.permission.WRITE_USER_DICTIONARY</code> |
| 703 | permission for inserting, updating, or deleting data. |
| 704 | </p> |
| 705 | <p> |
| 706 | To get the permissions needed to access a provider, an application requests them with a |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 707 | <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> |
| 708 | element in its manifest file. When the Android Package Manager installs the application, a user |
| 709 | must approve all of the permissions the application requests. If the user approves all of them, |
| 710 | Package Manager continues the installation; if the user doesn't approve them, Package Manager |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 711 | aborts the installation. |
| 712 | </p> |
| 713 | <p> |
| 714 | The following |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 715 | <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code> |
| 716 | element requests read access to the User Dictionary Provider: |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 717 | </p> |
| 718 | <pre> |
| 719 | <uses-permission android:name="android.permission.READ_USER_DICTIONARY"> |
| 720 | </pre> |
| 721 | <p> |
| 722 | The impact of permissions on provider access is explained in more detail in the |
| 723 | <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a> guide. |
| 724 | </p> |
| 725 | |
| 726 | |
| 727 | <!-- Inserting, Updating, and Deleting Data --> |
| 728 | <h2 id="Modifications">Inserting, Updating, and Deleting Data</h2> |
| 729 | <p> |
| 730 | In the same way that you retrieve data from a provider, you also use the interaction between |
| 731 | a provider client and the provider's {@link android.content.ContentProvider} to modify data. |
| 732 | You call a method of {@link android.content.ContentResolver} with arguments that are passed to |
| 733 | the corresponding method of {@link android.content.ContentProvider}. The provider and provider |
| 734 | client automatically handle security and inter-process communication. |
| 735 | </p> |
| 736 | <h3 id="Inserting">Inserting data</h3> |
| 737 | <p> |
| 738 | To insert data into a provider, you call the |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 739 | {@link android.content.ContentResolver#insert ContentResolver.insert()} |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 740 | method. This method inserts a new row into the provider and returns a content URI for that row. |
| 741 | This snippet shows how to insert a new word into the User Dictionary Provider: |
| 742 | </p> |
| 743 | <pre class="prettyprint"> |
| 744 | // Defines a new Uri object that receives the result of the insertion |
| 745 | Uri mNewUri; |
| 746 | |
| 747 | ... |
| 748 | |
| 749 | // Defines an object to contain the new values to insert |
| 750 | ContentValues mNewValues = new ContentValues(); |
| 751 | |
| 752 | /* |
| 753 | * Sets the values of each column and inserts the word. The arguments to the "put" |
| 754 | * method are "column name" and "value" |
| 755 | */ |
| 756 | mNewValues.put(UserDictionary.Words.APP_ID, "example.user"); |
| 757 | mNewValues.put(UserDictionary.Words.LOCALE, "en_US"); |
| 758 | mNewValues.put(UserDictionary.Words.WORD, "insert"); |
| 759 | mNewValues.put(UserDictionary.Words.FREQUENCY, "100"); |
| 760 | |
| 761 | mNewUri = getContentResolver().insert( |
| 762 | UserDictionary.Word.CONTENT_URI, // the user dictionary content URI |
| 763 | mNewValues // the values to insert |
| 764 | ); |
| 765 | </pre> |
| 766 | <p> |
| 767 | The data for the new row goes into a single {@link android.content.ContentValues} object, which |
| 768 | is similar in form to a one-row cursor. The columns in this object don't need to have the |
| 769 | same data type, and if you don't want to specify a value at all, you can set a column |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 770 | to <code>null</code> using {@link android.content.ContentValues#putNull ContentValues.putNull()}. |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 771 | </p> |
| 772 | <p> |
| 773 | The snippet doesn't add the <code>_ID</code> column, because this column is maintained |
| 774 | automatically. The provider assigns a unique value of <code>_ID</code> to every row that is |
| 775 | added. Providers usually use this value as the table's primary key. |
| 776 | </p> |
| 777 | <p> |
| 778 | The content URI returned in <code>newUri</code> identifies the newly-added row, with |
| 779 | the following format: |
| 780 | </p> |
| 781 | <pre> |
| 782 | content://user_dictionary/words/<id_value> |
| 783 | </pre> |
| 784 | <p> |
| 785 | The <code><id_value></code> is the contents of <code>_ID</code> for the new row. |
| 786 | Most providers can detect this form of content URI automatically and then perform the requested |
| 787 | operation on that particular row. |
| 788 | </p> |
| 789 | <p> |
| 790 | To get the value of <code>_ID</code> from the returned {@link android.net.Uri}, call |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 791 | {@link android.content.ContentUris#parseId ContentUris.parseId()}. |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 792 | </p> |
| 793 | <h3 id="Updating">Updating data</h3> |
| 794 | <p> |
| 795 | To update a row, you use a {@link android.content.ContentValues} object with the updated |
| 796 | values just as you do with an insertion, and selection criteria just as you do with a query. |
| 797 | The client method you use is |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 798 | {@link android.content.ContentResolver#update ContentResolver.update()}. You only need to add |
| 799 | values to the {@link android.content.ContentValues} object for columns you're updating. If you |
| 800 | want to clear the contents of a column, set the value to <code>null</code>. |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 801 | </p> |
| 802 | <p> |
| 803 | The following snippet changes all the rows whose locale has the language "en" to a |
| 804 | have a locale of <code>null</code>. The return value is the number of rows that were updated: |
| 805 | </p> |
| 806 | <pre> |
| 807 | // Defines an object to contain the updated values |
| 808 | ContentValues mUpdateValues = new ContentValues(); |
| 809 | |
| 810 | // Defines selection criteria for the rows you want to update |
| 811 | String mSelectionClause = UserDictionary.Words.LOCALE + "LIKE ?"; |
| 812 | String[] mSelectionArgs = {"en_%"}; |
| 813 | |
| 814 | // Defines a variable to contain the number of updated rows |
| 815 | int mRowsUpdated = 0; |
| 816 | |
| 817 | ... |
| 818 | |
| 819 | /* |
| 820 | * Sets the updated value and updates the selected words. |
| 821 | */ |
| 822 | mUpdateValues.putNull(UserDictionary.Words.LOCALE); |
| 823 | |
| 824 | mRowsUpdated = getContentResolver().update( |
| 825 | UserDictionary.Words.CONTENT_URI, // the user dictionary content URI |
| 826 | mUpdateValues // the columns to update |
| 827 | mSelectionClause // the column to select on |
| 828 | mSelectionArgs // the value to compare to |
| 829 | ); |
| 830 | </pre> |
| 831 | <p> |
| 832 | You should also sanitize user input when you call |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 833 | {@link android.content.ContentResolver#update ContentResolver.update()}. To learn more about |
| 834 | this, read the section <a href="#Injection">Protecting against malicious input</a>. |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 835 | </p> |
| 836 | <h3 id="Deleting">Deleting data</h3> |
| 837 | <p> |
| 838 | Deleting rows is similar to retrieving row data: you specify selection criteria for the rows |
| 839 | you want to delete and the client method returns the number of deleted rows. |
| 840 | The following snippet deletes rows whose appid matches "user". The method returns the |
| 841 | number of deleted rows. |
| 842 | </p> |
| 843 | <pre> |
| 844 | |
| 845 | // Defines selection criteria for the rows you want to delete |
| 846 | String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?"; |
| 847 | String[] mSelectionArgs = {"user"}; |
| 848 | |
| 849 | // Defines a variable to contain the number of rows deleted |
| 850 | int mRowsDeleted = 0; |
| 851 | |
| 852 | ... |
| 853 | |
| 854 | // Deletes the words that match the selection criteria |
| 855 | mRowsDeleted = getContentResolver().delete( |
| 856 | UserDictionary.Words.CONTENT_URI, // the user dictionary content URI |
| 857 | mSelectionClause // the column to select on |
| 858 | mSelectionArgs // the value to compare to |
| 859 | ); |
| 860 | </pre> |
| 861 | <p> |
| 862 | You should also sanitize user input when you call |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 863 | {@link android.content.ContentResolver#delete ContentResolver.delete()}. To learn more about |
| 864 | this, read the section <a href="#Injection">Protecting against malicious input</a>. |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 865 | </p> |
| 866 | <!-- Provider Data Types --> |
| 867 | <h2 id="DataTypes">Provider Data Types</h2> |
| 868 | <p> |
| 869 | Content providers can offer many different data types. The User Dictionary Provider offers only |
| 870 | text, but providers can also offer the following formats: |
| 871 | </p> |
| 872 | <ul> |
| 873 | <li> |
| 874 | integer |
| 875 | </li> |
| 876 | <li> |
| 877 | long integer (long) |
| 878 | </li> |
| 879 | <li> |
| 880 | floating point |
| 881 | </li> |
| 882 | <li> |
| 883 | long floating point (double) |
| 884 | </li> |
| 885 | </ul> |
| 886 | <p> |
| 887 | Another data type that providers often use is Binary Large OBject (BLOB) implemented as a |
| 888 | 64KB byte array. You can see the available data types by looking at the |
| 889 | {@link android.database.Cursor} class "get" methods. |
| 890 | </p> |
| 891 | <p> |
| 892 | The data type for each column in a provider is usually listed in its documentation. |
| 893 | The data types for the User Dictionary Provider are listed in the reference documentation |
| 894 | for its contract class {@link android.provider.UserDictionary.Words} (contract classes are |
| 895 | described in the section <a href="#ContractClasses">Contract Classes</a>). |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 896 | You can also determine the data type by calling {@link android.database.Cursor#getType |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 897 | Cursor.getType()}. |
| 898 | </p> |
| 899 | <p> |
| 900 | Providers also maintain MIME data type information for each content URI they define. You can |
| 901 | use the MIME type information to find out if your application can handle data that the |
| 902 | provider offers, or to choose a type of handling based on the MIME type. You usually need the |
| 903 | MIME type when you are working with a provider that contains complex |
| 904 | data structures or files. For example, the {@link android.provider.ContactsContract.Data} |
| 905 | table in the Contacts Provider uses MIME types to label the type of contact data stored in each |
| 906 | row. To get the MIME type corresponding to a content URI, call |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 907 | {@link android.content.ContentResolver#getType ContentResolver.getType()}. |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 908 | </p> |
| 909 | <p> |
| 910 | The section <a href="#MIMETypeReference">MIME Type Reference</a> describes the |
| 911 | syntax of both standard and custom MIME types. |
| 912 | </p> |
| 913 | |
| 914 | |
| 915 | <!-- Alternative Forms of Provider Access --> |
| 916 | <h2 id="AltForms">Alternative Forms of Provider Access</h2> |
| 917 | <p> |
| 918 | Three alternative forms of provider access are important in application development: |
| 919 | </p> |
| 920 | <ul> |
| 921 | <li> |
| 922 | <a href="#Batch">Batch access</a>: You can create a batch of access calls with methods in |
| 923 | the {@link android.content.ContentProviderOperation} class, and then apply them with |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 924 | {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}. |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 925 | </li> |
| 926 | <li> |
| 927 | Asynchronous queries: You should do queries in a separate thread. One way to do this is to |
| 928 | use a {@link android.content.CursorLoader} object. The examples in the |
Scott Main | 50e990c | 2012-06-21 17:14:39 -0700 | [diff] [blame] | 929 | <a href="{@docRoot}guide/components/loaders.html">Loaders</a> guide demonstrate |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 930 | how to do this. |
| 931 | </li> |
| 932 | <li> |
| 933 | <a href="#Intents">Data access via intents</a>: Although you can't send an intent |
| 934 | directly to a provider, you can send an intent to the provider's application, which is |
| 935 | usually the best-equipped to modify the provider's data. |
| 936 | </li> |
| 937 | </ul> |
| 938 | <p> |
| 939 | Batch access and modification via intents are described in the following sections. |
| 940 | </p> |
| 941 | <h3 id="Batch">Batch access</h3> |
| 942 | <p> |
| 943 | Batch access to a provider is useful for inserting a large number of rows, or for inserting |
| 944 | rows in multiple tables in the same method call, or in general for performing a set of |
| 945 | operations across process boundaries as a transaction (an atomic operation). |
| 946 | </p> |
| 947 | <p> |
| 948 | To access a provider in "batch mode", |
| 949 | you create an array of {@link android.content.ContentProviderOperation} objects and then |
| 950 | dispatch them to a content provider with |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 951 | {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}. You pass the |
| 952 | content provider's <em>authority</em> to this method, rather than a particular content URI. |
| 953 | This allows each {@link android.content.ContentProviderOperation} object in the array to work |
| 954 | against a different table. A call to {@link android.content.ContentResolver#applyBatch |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 955 | ContentResolver.applyBatch()} returns an array of results. |
| 956 | </p> |
| 957 | <p> |
| 958 | The description of the {@link android.provider.ContactsContract.RawContacts} contract class |
| 959 | includes a code snippet that demonstrates batch insertion. The |
| 960 | <a href="{@docRoot}resources/samples/ContactManager/index.html">Contact Manager</a> |
| 961 | sample application contains an example of batch access in its <code>ContactAdder.java</code> |
| 962 | source file. |
| 963 | </p> |
| 964 | <div class="sidebox-wrapper"> |
| 965 | <div class="sidebox"> |
| 966 | <h2>Displaying data using a helper app</h2> |
| 967 | <p> |
| 968 | If your application <em>does</em> have access permissions, you still may want to use an |
| 969 | intent to display data in another application. For example, the Calendar application accepts an |
| 970 | {@link android.content.Intent#ACTION_VIEW} intent, which displays a particular date or event. |
| 971 | This allows you to display calendar information without having to create your own UI. |
| 972 | To learn more about this feature, see the |
| 973 | <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar Provider</a> guide. |
| 974 | </p> |
| 975 | <p> |
| 976 | The application to which you send the intent doesn't have to be the application |
| 977 | associated with the provider. For example, you can retrieve a contact from the |
| 978 | Contact Provider, then send an {@link android.content.Intent#ACTION_VIEW} intent |
| 979 | containing the content URI for the contact's image to an image viewer. |
| 980 | </p> |
| 981 | </div> |
| 982 | </div> |
| 983 | <h3 id="Intents">Data access via intents</h3> |
| 984 | <p> |
| 985 | Intents can provide indirect access to a content provider. You allow the user to access |
| 986 | data in a provider even if your application doesn't have access permissions, either by |
| 987 | getting a result intent back from an application that has permissions, or by activating an |
| 988 | application that has permissions and letting the user do work in it. |
| 989 | </p> |
| 990 | <h4>Getting access with temporary permissions</h4> |
| 991 | <p> |
| 992 | You can access data in a content provider, even if you don't have the proper access |
| 993 | permissions, by sending an intent to an application that does have the permissions and |
| 994 | receiving back a result intent containing "URI" permissions. |
| 995 | These are permissions for a specific content URI that last until the activity that receives |
| 996 | them is finished. The application that has permanent permissions grants temporary |
| 997 | permissions by setting a flag in the result intent: |
| 998 | </p> |
| 999 | <ul> |
| 1000 | <li> |
| 1001 | <strong>Read permission:</strong> |
| 1002 | {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} |
| 1003 | </li> |
| 1004 | <li> |
| 1005 | <strong>Write permission:</strong> |
| 1006 | {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} |
| 1007 | </li> |
| 1008 | </ul> |
| 1009 | <p class="note"> |
| 1010 | <strong>Note:</strong> These flags don't give general read or write access to the provider |
| 1011 | whose authority is contained in the content URI. The access is only for the URI itself. |
| 1012 | </p> |
| 1013 | <p> |
| 1014 | A provider defines URI permissions for content URIs in its manifest, using the |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 1015 | <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">android:grantUriPermission</a></code> |
| 1016 | attribute of the |
| 1017 | <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code> |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 1018 | element, as well as the |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 1019 | <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"><grant-uri-permission></a></code> |
| 1020 | child element of the |
| 1021 | <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code> |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 1022 | element. The URI permissions mechanism is explained in more detail in the |
| 1023 | <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a> guide, |
| 1024 | in the section "URI Permissions". |
| 1025 | </p> |
| 1026 | <p> |
| 1027 | For example, you can retrieve data for a contact in the Contacts Provider, even if you don't |
| 1028 | have the {@link android.Manifest.permission#READ_CONTACTS} permission. You might want to do |
| 1029 | this in an application that sends e-greetings to a contact on his or her birthday. Instead of |
| 1030 | requesting {@link android.Manifest.permission#READ_CONTACTS}, which gives you access to all of |
| 1031 | the user's contacts and all of their information, you prefer to let the user control which |
| 1032 | contacts are used by your application. To do this, you use the following process: |
| 1033 | </p> |
| 1034 | <ol> |
| 1035 | <li> |
| 1036 | Your application sends an intent containing the action |
| 1037 | {@link android.content.Intent#ACTION_PICK} and the "contacts" MIME type |
| 1038 | {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE}, using the |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 1039 | method {@link android.app.Activity#startActivityForResult |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 1040 | startActivityForResult()}. |
| 1041 | </li> |
| 1042 | <li> |
| 1043 | Because this intent matches the intent filter for the |
| 1044 | People app's "selection" activity, the activity will come to the foreground. |
| 1045 | </li> |
| 1046 | <li> |
| 1047 | In the selection activity, the user selects a |
| 1048 | contact to update. When this happens, the selection activity calls |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 1049 | {@link android.app.Activity#setResult setResult(resultcode, intent)} |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 1050 | to set up a intent to give back to your application. The intent contains the content URI |
| 1051 | of the contact the user selected, and the "extras" flags |
| 1052 | {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}. These flags grant URI |
| 1053 | permission to your app to read data for the contact pointed to by the |
| 1054 | content URI. The selection activity then calls {@link android.app.Activity#finish()} to |
| 1055 | return control to your application. |
| 1056 | </li> |
| 1057 | <li> |
| 1058 | Your activity returns to the foreground, and the system calls your activity's |
Joe Malin | 955d7cc | 2012-08-09 18:34:12 -0700 | [diff] [blame] | 1059 | {@link android.app.Activity#onActivityResult onActivityResult()} |
Joe Malin | a2a46f6 | 2011-11-14 10:51:16 -0800 | [diff] [blame] | 1060 | method. This method receives the result intent created by the selection activity in |
| 1061 | the People app. |
| 1062 | </li> |
| 1063 | <li> |
| 1064 | With the content URI from the result intent, you can read the contact's data |
| 1065 | from the Contacts Provider, even though you didn't request permanent read access permission |
| 1066 | to the provider in your manifest. You can then get the contact's birthday information |
| 1067 | or his or her email address and then send the e-greeting. |
| 1068 | </li> |
| 1069 | </ol> |
| 1070 | <h4>Using another application</h4> |
| 1071 | <p> |
| 1072 | A simple way to allow the user to modify data to which you don't have access permissions is to |
| 1073 | activate an application that has permissions and let the user do the work there. |
| 1074 | </p> |
| 1075 | <p> |
| 1076 | For example, the Calendar application accepts an |
| 1077 | {@link android.content.Intent#ACTION_INSERT} intent, which allows you to activate the |
| 1078 | application's insert UI. You can pass "extras" data in this intent, which the application |
| 1079 | uses to pre-populate the UI. Because recurring events have a complex syntax, the preferred |
| 1080 | way of inserting events into the Calendar Provider is to activate the Calendar app with an |
| 1081 | {@link android.content.Intent#ACTION_INSERT} and then let the user insert the event there. |
| 1082 | </p> |
| 1083 | <!-- Contract Classes --> |
| 1084 | <h2 id="ContractClasses">Contract Classes</h2> |
| 1085 | <p> |
| 1086 | A contract class defines constants that help applications work with the content URIs, column |
| 1087 | names, intent actions, and other features of a content provider. Contract classes are not |
| 1088 | included automatically with a provider; the provider's developer has to define them and then |
| 1089 | make them available to other developers. Many of the providers included with the Android |
| 1090 | platform have corresponding contract classes in the package {@link android.provider}. |
| 1091 | </p> |
| 1092 | <p> |
| 1093 | For example, the User Dictionary Provider has a contract class |
| 1094 | {@link android.provider.UserDictionary} containing content URI and column name constants. The |
| 1095 | content URI for the "words" table is defined in the constant |
| 1096 | {@link android.provider.UserDictionary.Words#CONTENT_URI UserDictionary.Words.CONTENT_URI}. |
| 1097 | The {@link android.provider.UserDictionary.Words} class also contains column name constants, |
| 1098 | which are used in the example snippets in this guide. For example, a query projection can be |
| 1099 | defined as: |
| 1100 | </p> |
| 1101 | <pre> |
| 1102 | String[] mProjection = |
| 1103 | { |
| 1104 | UserDictionary.Words._ID, |
| 1105 | UserDictionary.Words.WORD, |
| 1106 | UserDictionary.Words.LOCALE |
| 1107 | }; |
| 1108 | </pre> |
| 1109 | <p> |
| 1110 | Another contract class is {@link android.provider.ContactsContract} for the Contacts Provider. |
| 1111 | The reference documentation for this class includes example code snippets. One of its |
| 1112 | subclasses, {@link android.provider.ContactsContract.Intents.Insert}, is a contract |
| 1113 | class that contains constants for intents and intent data. |
| 1114 | </p> |
| 1115 | |
| 1116 | |
| 1117 | <!-- MIME Type Reference --> |
| 1118 | <h2 id="MIMETypeReference">MIME Type Reference</h2> |
| 1119 | <p> |
| 1120 | Content providers can return standard MIME media types, or custom MIME type strings, or both. |
| 1121 | </p> |
| 1122 | <p> |
| 1123 | MIME types have the format |
| 1124 | </p> |
| 1125 | <pre> |
| 1126 | <em>type</em>/<em>subtype</em> |
| 1127 | </pre> |
| 1128 | <p> |
| 1129 | For example, the well-known MIME type <code>text/html</code> has the <code>text</code> type and |
| 1130 | the <code>html</code> subtype. If the provider returns this type for a URI, it means that a |
| 1131 | query using that URI will return text containing HTML tags. |
| 1132 | </p> |
| 1133 | <p> |
| 1134 | Custom MIME type strings, also called "vendor-specific" MIME types, have more |
| 1135 | complex <em>type</em> and <em>subtype</em> values. The <em>type</em> value is always |
| 1136 | </p> |
| 1137 | <pre> |
| 1138 | vnd.android.cursor.<strong>dir</strong> |
| 1139 | </pre> |
| 1140 | <p> |
| 1141 | for multiple rows, or |
| 1142 | </p> |
| 1143 | <pre> |
| 1144 | vnd.android.cursor.<strong>item</strong> |
| 1145 | </pre> |
| 1146 | <p> |
| 1147 | for a single row. |
| 1148 | </p> |
| 1149 | <p> |
| 1150 | The <em>subtype</em> is provider-specific. The Android built-in providers usually have a simple |
| 1151 | subtype. For example, the when the Contacts application creates a row for a telephone number, |
| 1152 | it sets the following MIME type in the row: |
| 1153 | </p> |
| 1154 | <pre> |
| 1155 | vnd.android.cursor.item/phone_v2 |
| 1156 | </pre> |
| 1157 | <p> |
| 1158 | Notice that the subtype value is simply <code>phone_v2</code>. |
| 1159 | </p> |
| 1160 | <p> |
| 1161 | Other provider developers may create their own pattern of subtypes based on the provider's |
| 1162 | authority and table names. For example, consider a provider that contains train timetables. |
| 1163 | The provider's authority is <code>com.example.trains</code>, and it contains the tables |
| 1164 | Line1, Line2, and Line3. In response to the content URI |
| 1165 | </p> |
| 1166 | <p> |
| 1167 | <pre> |
| 1168 | content://com.example.trains/Line1 |
| 1169 | </pre> |
| 1170 | <p> |
| 1171 | for table Line1, the provider returns the MIME type |
| 1172 | </p> |
| 1173 | <pre> |
| 1174 | vnd.android.cursor.<strong>dir</strong>/vnd.example.line1 |
| 1175 | </pre> |
| 1176 | <p> |
| 1177 | In response to the content URI |
| 1178 | </p> |
| 1179 | <pre> |
| 1180 | content://com.example.trains/Line2/5 |
| 1181 | </pre> |
| 1182 | <p> |
| 1183 | for row 5 in table Line2, the provider returns the MIME type |
| 1184 | </p> |
| 1185 | <pre> |
| 1186 | vnd.android.cursor.<strong>item</strong>/vnd.example.line2 |
| 1187 | </pre> |
| 1188 | <p> |
| 1189 | Most content providers define contract class constants for the MIME types they use. The |
| 1190 | Contacts Provider contract class {@link android.provider.ContactsContract.RawContacts}, |
| 1191 | for example, defines the constant |
| 1192 | {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} for the MIME type of |
| 1193 | a single raw contact row. |
| 1194 | </p> |
| 1195 | <p> |
| 1196 | Content URIs for single rows are described in the section |
| 1197 | <a href="#ContentURIs">Content URIs</a>. |
| 1198 | </p> |