1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
|
page.title=Content Providers
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>Key classes</h2>
<ol>
<li>{@link android.content.ContentProvider}</li>
<li>{@link android.content.ContentResolver}</li>
<li>{@link android.database.Cursor}</li>
</ol>
<h2>In this document</h2>
<ol>
<li><a href="#basics">Content provider basics</a></li>
<li><a href="#querying">Querying a content provider</a></li>
<li><a href="#modifying">Modifying data in a provider</a></li>
<li><a href="#creating">Creating a content provider</a></li>
<li><a href="#urisum">Content URI summary</a></li>
</ol>
</div>
</div>
<p>
Content providers store and retrieve data and make it accessible to all
applications. They're the only way to share data across applications; there's
no common storage area that all Android packages can access.
</p>
<p>
Android ships with a number of content providers for common data types
(audio, video, images, personal contact information, and so on). You can
see some of them listed in the {@link android.provider android.provider}
package. You can query these providers for the data they contain (although,
for some, you must acquire the proper permission to read the data).
</p>
<p>
If you want to make your own data public, you have two options: You can
create your own content provider (a {@link android.content.ContentProvider}
subclass) or you can add the data to an existing provider — if there's
one that controls the same type of data and you have permission to write to it.
</p>
<p>
This document is an introduction to using content providers. After a
brief discussion of the fundamentals, it explores how to query a content
provider, how to modify data controlled by a provider, and how to create
a content provider of your own.
</p>
<h2><a name="basics"></a>Content Provider Basics</h2>
<p>
How a content provider actually stores its data under the covers is
up to its designer. But all content providers implement a common interface
for querying the provider and returning results — as well as for
adding, altering, and deleting data.
</p>
<p>
It's an interface that clients use indirectly, most generally through
{@link android.content.ContentResolver} objects. You get a ContentResolver
by calling <code>{@link android.content.Context#getContentResolver
getContentResolver()}</code> from within the implementation of an Activity
or other application component:
</p>
<pre>ContentResolver cr = getContentResolver();</pre>
<p>
You can then use the ContentResolver's methods to interact with whatever
content providers you're interested in.
</p>
<p>
When a query is initiated, the Android system identifies the content provider
that's the target of the query and makes sure that it is up and running.
The system instantiates all ContentProvider objects; you never need to do it
on your own. In fact, you never deal directly with ContentProvider objects
at all. Typically, there's just a single instance of each type of
ContentProvider. But it can communicate with multiple ContentResolver objects
in different applications and processes. The interaction between processes is
handled by the ContentResolver and ContentProvider classes.
</p>
<h3>The data model</h3>
<p>
Content providers expose their data as a simple table on a database model,
where each row is a record and each column is data of a particular type
and meaning. For example, information about people and their phone numbers
might be exposed as follows:
</p>
<table>
<tr>
<th scope="col">_ID</th>
<th scope="col">NUMBER</th>
<th scope="col">NUMBER_KEY</th>
<th scope="col">LABEL</th>
<th scope="col">NAME</th>
<th scope="col">TYPE</th>
</tr>
<tr>
<td>13</td>
<td>(425) 555 6677</td>
<td>425 555 6677</td>
<td>Kirkland office</td>
<td>Bully Pulpit</td>
<td>{@code TYPE_WORK}</td>
</tr>
<tr>
<td>44</td>
<td>(212) 555-1234</td>
<td>212 555 1234</td>
<td>NY apartment</td>
<td>Alan Vain</td>
<td>{@code TYPE_HOME}</td>
</tr>
<tr>
<td>45</td>
<td>(212) 555-6657</td>
<td>212 555 6657</td>
<td>Downtown office</td>
<td>Alan Vain</td>
<td>{@code TYPE_MOBILE}</td>
</tr>
<tr>
<td>53</td>
<td>201.555.4433</td>
<td>201 555 4433</td>
<td>Love Nest</td>
<td>Rex Cars</td>
<td>{@code TYPE_HOME}</td>
</tr>
</table>
<p>
Every record includes a numeric {@code _ID} field that uniquely identifies
the record within the table. IDs can be used to match records in related
tables — for example, to find a person's phone number in one table
and pictures of that person in another.
</p>
<p>
A query returns a {@link android.database.Cursor} object that can move from
record to record and column to column to read the contents of each field.
It has specialized methods for reading each type of data. So, to read a field,
you must know what type of data the field contains. (There's more on query
results and Cursor objects later.)
</p>
<h3><a name="uri"></a>URIs</h3>
<p>
Each content provider exposes a public URI (wrapped as a {@link android.net.Uri}
object) that uniquely identifies its data set. A content provider that controls
multiple data sets (multiple tables) exposes a separate URI for each one. All
URIs for providers begin with the string "{@code content://}". The {@code content:}
scheme identifies the data as being controlled by a content provider.
</p>
<p>
If you're defining a content provider, it's a good idea to also define a
constant for its URI, to simplify client code and make future updates cleaner.
Android defines {@code CONTENT_URI} constants for all the providers that come
with the platform. For example, the URI for the table that matches
phone numbers to people and the URI for the table that holds pictures of
people (both controlled by the Contacts content provider) are:
</p>
<p>
<p style="margin-left: 2em">{@code android.provider.Contacts.Phones.CONTENT_URI}
<br/>{@code android.provider.Contacts.Photos.CONTENT_URI}
</p>
<p>
The URI constant is used in all interactions with the content provider.
Every {@link android.content.ContentResolver} method takes the URI
as its first argument. It's what identifies which provider the ContentResolver
should talk to and which table of the provider is being targeted.
</p>
<h2><a name="querying"></a>Querying a Content Provider</h2>
<p>
You need three pieces of information to query a content provider:
</p>
<ul>
<li>The URI that identifies the provider</li>
<li>The names of the data fields you want to receive</li>
<li>The data types for those fields</li>
</ul>
<p>
If you're querying a particular record, you also need the ID for that record.
</p>
<h3>Making the query</h3>
<p>
To query a content provider, you can use either the
<code>{@link android.content.ContentResolver#query ContentResolver.query()}</code>
method or the <code>{@link android.app.Activity#managedQuery
Activity.managedQuery()}</code> method.
Both methods take the same set of arguments, and both return a
Cursor object. However, {@code managedQuery()}
causes the activity to manage the life cycle of the Cursor. A managed Cursor
handles all of the niceties, such as unloading itself when the activity pauses,
and requerying itself when the activity restarts. You can ask an Activity to
begin managing an unmanaged Cursor object for you by calling
<code>{@link android.app.Activity#startManagingCursor
Activity.startManagingCursor()}</code>.
</p>
<p>
The first argument to either <code>{@link android.content.ContentResolver#query query()}</code>
or <code>{@link android.app.Activity#managedQuery managedQuery()}</code> is the provider URI
— the {@code CONTENT_URI} constant that identifies a particular
ContentProvider and data set (see <a href="#uri">URIs</a> earlier).
</p>
<p>
To restrict a query to just one record, you can append the {@code _ID} value for
that record to the URI — that is, place a string matching the ID as the
last segment of the path part of the URI. For example, if the ID is 23,
the URI would be:
</p>
<p style="margin-left: 2em">{@code content://. . . ./23}</p>
<p>
There are some helper methods, particularly
<code>{@link android.content.ContentUris#withAppendedId
ContentUris.withAppendedId()}</code> and <code>{@link
android.net.Uri#withAppendedPath Uri.withAppendedPath()}</code>,
that make it easy to append an ID to a URI. Both are static methods that return
a Uri object with the ID added. So, for example, if you were looking for record
23 in the database of people contacts, you might construct a query as follows:
</p>
<pre>
import android.provider.Contacts.People;
import android.content.ContentUris;
import android.net.Uri;
import android.database.Cursor;
// Use the ContentUris method to produce the base URI for the contact with _ID == 23.
Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23);
// Alternatively, use the Uri method to produce the base URI.
// It takes a string rather than an integer.
Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23");
// Then query for this specific record:
Cursor cur = managedQuery(myPerson, null, null, null, null);
</pre>
<p>
The other arguments to the <code>{@link android.content.ContentResolver#query query()}</code>
and <code>{@link android.app.Activity#managedQuery managedQuery()}</code> methods delimit
the query in more detail. They are:
</p>
<ul>
<li>The names of the data columns that should be returned. A {@code null}
value returns all columns. Otherwise, only columns that are listed by name
are returned. All the content providers that come with the platform define
constants for their columns. For example, the
{@link android.provider.Contacts.Phones android.provider.Contacts.Phones} class
defines constants for the names of the columns in the phone table illustrated
earlier &mdash {@code _ID}, {@code NUMBER}, {@code NUMBER_KEY}, {@code NAME},
and so on.</li>
<li><p>A filter detailing which rows to return, formatted as an SQL {@code WHERE}
clause (excluding the {@code WHERE} itself). A {@code null} value returns
all rows (unless the URI limits the query to a single record).</p></li>
<li><p>Selection arguments.</p></li>
<li><p>A sorting order for the rows that are returned, formatted as an SQL
{@code ORDER BY} clause (excluding the {@code ORDER BY} itself). A {@code null}
value returns the records in the default order for the table, which may be
unordered.</p></li>
</ul>
<p>
Let's look at an example query to retrieve a list of contact names and their
primary phone numbers:
</p>
<pre>
import android.provider.Contacts.People;
import android.database.Cursor;
// Form an array specifying which columns to return.
String[] projection = new String[] {
People._ID,
People._COUNT,
People.NAME,
People.NUMBER
};
// Get the base URI for the People table in the Contacts content provider.
Uri contacts = People.CONTENT_URI;
// Make the query.
Cursor managedCursor = managedQuery(contacts,
projection, // Which columns to return
null, // Which rows to return (all rows)
null, // Selection arguments (none)
// Put the results in ascending order by name
People.NAME + " ASC");
</pre>
<p>
This query retrieves data from the People table of the Contacts content
provider. It gets the name, primary phone number, and unique record ID for
each contact. It also reports the number of records that are returned as
the {@code _COUNT} field of each record.
</p>
<p>
The constants for the names of the columns are defined in various interfaces
— {@code _ID} and {@code _COUNT} in
{@link android.provider.BaseColumns BaseColumns}, {@code NAME} in {@link android.provider.Contacts.PeopleColumns PeopleColumns}, and {@code NUMBER}
in {@link android.provider.Contacts.PhonesColumns PhoneColumns}. The
{@link android.provider.Contacts.People Contacts.People} class implements
each of these interfaces, which is why the code example above could refer
to them using just the class name.
</p>
<h3>What a query returns</h3>
<p>
A query returns a set of zero or more database records. The names of the
columns, their default order, and their data types are specific to each
content provider.
But every provider has an {@code _ID} column, which holds a unique numeric
ID for each record. Every provider can also report the number
of records returned as the {@code _COUNT} column; its value
is the same for all rows.
</p>
<p>
Here is an example result set for the query in the previous section:
</p>
<table border="1">
<tbody>
<tr>
<th scope="col">_ID</th>
<th scope="col">_COUNT</th>
<th scope="col">NAME</th>
<th scope="col">NUMBER</th>
</tr>
<tr>
<td>44</td>
<td>3</td>
<td>Alan Vain</td>
<td>212 555 1234</td>
</tr>
<tr>
<td>13</td>
<td>3</td>
<td>Bully Pulpit</td>
<td>425 555 6677</td>
</tr>
<tr>
<td>53</td>
<td>3</td>
<td>Rex Cars</td>
<td>201 555 4433</td>
</tr>
</tbody>
</table>
<p>
The retrieved data is exposed by a {@link android.database.Cursor Cursor}
object that can be used to iterate backward or forward through the result
set. You can use this object only to read the data. To add, modify, or
delete data, you must use a ContentResolver object.
</p>
<h3>Reading retrieved data</h3>
<p>
The Cursor object returned by a query provides access to a recordset of
results. If you have queried for a specific record by ID, this set will
contain only one value. Otherwise, it can contain multiple values.
(If there are no matches, it can also be empty.) You
can read data from specific fields in the record, but you must know the
data type of the field, because the Cursor object has a separate method
for reading each type of data — such as <code>{@link
android.database.Cursor#getString getString()}</code>, <code>{@link
android.database.Cursor#getInt getInt()}</code>, and <code>{@link
android.database.Cursor#getFloat getFloat()}</code>.
(However, for most types, if you call the method for reading strings,
the Cursor object will give you the String representation of the data.)
The Cursor lets you request the column name from the index of the column,
or the index number from the column name.
</p>
<p>
The following snippet demonstrates reading names and phone numbers from
the query illustrated earlier:
</p>
<pre>
import android.provider.Contacts.People;
private void getColumnData(Cursor cur){
if (cur.moveToFirst()) {
String name;
String phoneNumber;
int nameColumn = cur.getColumnIndex(People.NAME);
int phoneColumn = cur.getColumnIndex(People.NUMBER);
String imagePath;
do {
// Get the field values
name = cur.getString(nameColumn);
phoneNumber = cur.getString(phoneColumn);
// Do something with the values.
...
} while (cur.moveToNext());
}
}
</pre>
<p>
If a query can return binary data, such as an image or sound, the data
may be directly entered in the table or the table entry for that data may be
a string specifying a {@code content:} URI that you can use to get the data.
In general, smaller amounts of data (say, from 20 to 50K or less) are most often
directly entered in the table and can be read by calling
<code>{@link android.database.Cursor#getBlob Cursor.getBlob()}</code>.
It returns a byte array.
</p>
<p>
If the table entry is a {@code content:} URI, you should never try to open
and read the file directly (for one thing, permissions problems can make this
fail). Instead, you should call
<code>{@link android.content.ContentResolver#openInputStream
ContentResolver.openInputStream()}</code> to get an
{@link java.io.InputStream} object that you can use to read the data.
</p>
<h2><a name="modifying"></a>Modifying Data</h2>
<p>
Data kept by a content provider can be modified by:
</p>
<ul>
<p><li>Adding new records</li>
<li>Adding new values to existing records</li>
<li>Batch updating existing records</li>
<li>Deleting records</li>
</ul>
<p>
All data modification is accomplished using {@link android.content.ContentResolver}
methods. Some content providers require a more restrictive permission for writing
data than they do for reading it. If you don't have permission to write to a
content provider, the ContentResolver methods will fail.
</p>
<h3>Adding records</h3>
<p>
To add a new record to a content provider, first set up a map of key-value pairs
in a {@link android.content.ContentValues} object, where each key matches
the name of a column in the content provider and the value is the desired
value for the new record in that column. Then call <code>{@link
android.content.ContentResolver#insert ContentResolver.insert()}</code> and pass
it the URI of the provider and the ContentValues map. This method returns
the full URI of the new record — that is, the provider's URI with
the appended ID for the new record. You can then use this URI to query and
get a Cursor over the new record, and to further modify the record.
Here's an example:
</p>
<pre>
import android.provider.Contacts.People;
import android.content.ContentResolver;
import android.content.ContentValues;
ContentValues values = new ContentValues();
// Add Abraham Lincoln to contacts and make him a favorite.
values.put(People.NAME, "Abraham Lincoln");
// 1 = the new contact is added to favorites
// 0 = the new contact is not added to favorites
values.put(People.STARRED, 1);
Uri uri = getContentResolver().insert(People.CONTENT_URI, values);
</pre>
<h3>Adding new values</h3>
<p>
Once a record exists, you can add new information to it or modify
existing information. For example, the next step in the example above would
be to add contact information — like a phone number or an IM or e-mail
address — to the new entry.
</p>
<p>
The best way to add to a record in the Contacts database is to append
the name of the table where the new data goes to the URI for the
record, then use the amended URI to add the new data values. Each
Contacts table exposes a name for this purpose as a {@code
CONTENT_DIRECTORY} constant. The following code continues the previous
example by adding a phone number and e-mail address for the record
just created:
</p>
<pre>
Uri phoneUri = null;
Uri emailUri = null;
// Add a phone number for Abraham Lincoln. Begin with the URI for
// the new record just returned by insert(); it ends with the _ID
// of the new record, so we don't have to add the ID ourselves.
// Then append the designation for the phone table to this URI,
// and use the resulting URI to insert the phone number.
phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);
values.clear();
values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE);
values.put(People.Phones.NUMBER, "1233214567");
getContentResolver().insert(phoneUri, values);
// Now add an email address in the same way.
emailUri = Uri.withAppendedPath(uri, People.ContactMethods.CONTENT_DIRECTORY);
values.clear();
// ContactMethods.KIND is used to distinguish different kinds of
// contact methods, such as email, IM, etc.
values.put(People.ContactMethods.KIND, Contacts.KIND_EMAIL);
values.put(People.ContactMethods.DATA, "test@example.com");
values.put(People.ContactMethods.TYPE, People.ContactMethods.TYPE_HOME);
getContentResolver().insert(emailUri, values);
</pre>
<p>
You can place small amounts of binary data into a table by calling
the version of <code>{@link android.content.ContentValues#put
ContentValues.put()}</code> that takes a byte array.
That would work for a small icon-like image or a short audio clip, for example.
However, if you have a large amount of binary data to add, such as a photograph
or a complete song, put a {@code content:} URI for the data in the table and call
<code>{@link android.content.ContentResolver#openOutputStream
ContentResolver.openOutputStream()}</code>
with the file's URI. (That causes the content provider to store the data
in a file and record the file path in a hidden field of the record.)
</p>
<p>
In this regard, the {@link android.provider.MediaStore} content
provider, the main provider that dispenses image, audio, and video
data, employs a special convention: The same URI that is used with
{@code query()} or {@code managedQuery()} to get meta-information
about the binary data (such as, the caption of a photograph or the
date it was taken) is used with {@code openInputStream()}
to get the data itself. Similarly, the same URI that is used with
{@code insert()} to put meta-information into a MediaStore record
is used with {@code openOutputStream()} to place the binary data there.
The following code snippet illustrates this convention:
</p>
<pre>
import android.provider.MediaStore.Images.Media;
import android.content.ContentValues;
import java.io.OutputStream;
// Save the name and description of an image in a ContentValues map.
ContentValues values = new ContentValues(3);
values.put(Media.DISPLAY_NAME, "road_trip_1");
values.put(Media.DESCRIPTION, "Day 1, trip to Los Angeles");
values.put(Media.MIME_TYPE, "image/jpeg");
// Add a new record without the bitmap, but with the values just set.
// insert() returns the URI of the new record.
Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values);
// Now get a handle to the file for that record, and save the data into it.
// Here, sourceBitmap is a Bitmap object representing the file to save to the database.
try {
OutputStream outStream = getContentResolver().openOutputStream(uri);
sourceBitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream);
outStream.close();
} catch (Exception e) {
Log.e(TAG, "exception while writing image", e);
}
</pre>
<h3>Batch updating records</h3>
<p>
To batch update a group of records (for example, to change "NY" to "New York"
in all fields), call the <code>{@link
android.content.ContentResolver#update ContentResolver.update()}</code>
method with the columns and values to change.
</p>
<h3><a name="deletingrecord"></a>Deleting a record</h3>
<p>
To delete a single record, call {<code>{@link
android.content.ContentResolver#delete ContentResolver.delete()}</code>
with the URI of a specific row.
</p>
<p>
To delete multiple rows, call <code>{@link
android.content.ContentResolver#delete ContentResolver.delete()}</code>
with the URI of the type of record to delete (for example, {@code android.provider.Contacts.People.CONTENT_URI}) and an SQL {@code WHERE}
clause defining which rows to delete. (<i><b>Caution</b>:
Be sure to include a valid {@code WHERE} clause if you're deleting a general
type, or you risk deleting more records than you intended!</i>).
</p>
<h2><a name="creating"></a>Creating a Content Provider</h2>
<p>
To create a content provider, you must:
</p>
<ul>
<li>Set up a system for storing the data. Most content providers
store their data using Android's file storage methods or SQLite databases,
but you can store your data any way you want. Android provides the
{@link android.database.sqlite.SQLiteOpenHelper SQLiteOpenHelper}
class to help you create a database and {@link
android.database.sqlite.SQLiteDatabase SQLiteDatabase} to manage it.</li>
<li><p>Extend the {@link android.content.ContentProvider} class to provide
access to the data.</p></li>
<li><p>Declare the content provider in the manifest file for your
application (AndroidManifest.xml).</p></li>
</ul>
<p>
The following sections have notes on the last two of these tasks.
</p>
<h3>Extending the ContentProvider class</h3>
<p>
You define a {@link android.content.ContentProvider} subclass to
expose your data to others using the conventions expected by
ContentResolver and Cursor objects. Principally, this means
implementing six abstract methods declared in the ContentProvider class:
</p>
<p style="margin-left: 2em">{@code query()}
<br/>{@code insert()}
<br/>{@code update()}
<br/>{@code delete()}
<br/>{@code getType()}
<br/>{@code onCreate()}</p>
<p>
The {@code query()} method must return a {@link android.database.Cursor} object
that can iterate over the requested data. Cursor itself is an interface, but
Android provides some ready-made Cursor objects that you can use. For example,
{@link android.database.sqlite.SQLiteCursor} can iterate over data stored in
an SQLite database. You get the Cursor object by calling any of the {@link
android.database.sqlite.SQLiteDatabase SQLiteDatabase} class's {@code query()}
methods. There are other Cursor implementations — such as {@link
android.database.MatrixCursor} — for data not stored in a database.
</p>
<p>
Because these ContentProvider methods can be called from
various ContentResolver objects in different processes and threads,
they must be implemented in a thread-safe manner.
</p>
<p>
As a courtesy, you might also want to call <code>{@link android.content.ContentResolver#notifyChange(android.net.Uri,android.database.ContentObserver)
ContentResolver.notifyChange()}</code> to notify listeners when there are
modifications to the data.
</p>
<p>
Beyond defining the subclass itself, there are other steps you should take
to simplify the work of clients and make the class more accessible:
</p>
<ul>
<li>Define a {@code public static final} {@link android.net.Uri}
named {@code CONTENT_URI}. This is the string that represents the full
{@code content:} URI that your content provider handles. You must define a
unique string for this value. The best solution is to use the fully-qualified
class name of the content provider (made lowercase). So, for example, the
URI for a TransportationProvider class could be defined as follows:
<pre>public static final Uri CONTENT_URI =
Uri.parse("content://com.example.codelab.transportationprovider");</pre>
<p>
If the provider has subtables, also define {@code CONTENT_URI} constants for
each of the subtables. These URIs should all have the same authority (since
that identifies the content provider), and be distinguished only by their paths.
For example:
</p>
<p style="margin-left: 2em">{@code content://com.example.codelab.transportationprovider/train}
<br/>{@code content://com.example.codelab.transportationprovider/air/domestic}
<br/>{@code content://com.example.codelab.transportationprovider/air/international}</p>
<p>
For an overview of {@code content:} URIs, see the <a href="#urisum">Content URI
Summary</a> at the end of this document.
</p></li>
<li><p>Define the column names that the content provider will return to clients.
If you are using an underlying database, these column names are typically
identical to the SQL database column names they represent. Also define
{@code public static} String constants that clients can use to specify
the columns in queries and other instructions.
</p>
<p>
Be sure to include an integer column named "{@code _id}"
(with the constant {@code _ID}) for
the IDs of the records. You should have this field whether or not you have
another field (such as a URL) that is also unique among all records. If
you're using the SQLite database, the {@code _ID} field should be the
following type:
</p>
<p style="margin-left: 2em">{@code INTEGER PRIMARY KEY AUTOINCREMENT}</p>
<p>
The {@code AUTOINCREMENT} descriptor is optional. But without it, SQLite
increments an ID counter field to the next number above the largest
existing number in the column. If you delete the last row, the next row added
will have the same ID as the deleted row. {@code AUTOINCREMENT} avoids this
by having SQLite increment to the next largest value whether deleted or not.
</p>
</li>
<li><p>Carefully document the data type of each column. Clients need this
information to read the data.</p></li>
<li><p>If you are handling a new data type, you must define a new MIME type
to return in your implementation of <code>{@link
android.content.ContentProvider#getType ContentProvider.getType()}</code>.
The type depends in part on whether or not the {@code content:} URI submitted
to {@code getType()} limits the request to a specific record. There's one
form of the MIME type for a single record and another for multiple records.
Use the {@link android.net.Uri Uri} methods to help determine what is being
requested. Here is the general format for each type:</p></li>
<ul>
<li><p>For a single record: {@code vnd.android.cursor.item/vnd.<em>yourcompanyname.contenttype</em}</p>
<p>For example, a request for train record 122, like this URI,</p>
<p style="margin-left: 2em">{@code content://com.example.transportationprovider/trains/122}</p>
<p>might return this MIME type:</p>
<p style="margin-left: 2em">{@code vnd.android.cursor.item/vnd.example.rail}</p>
</li>
<li><p>For multiple records: {@code vnd.android.cursor.dir/vnd.<em>yourcompanyname.contenttype</em>}</p>
<p>For example, a request for all train records, like the following URI,</p>
<p style="margin-left: 2em">{@code content://com.example.transportationprovider/trains}</p>
<p>might return this MIME type:</p>
<p style="margin-left: 2em">{@code vnd.android.cursor.dir/vnd.example.rail}</p>
</li>
</ul>
<li><p>If you are exposing byte data that's too big to put in the table itself
— such as a large bitmap file — the field that exposes the
data to clients should actually contain a {@code content:} URI string.
This is the field that gives clients access to the data file. The record
should also have another field, named "{@code _data}" that lists the exact file
path on the device for that file. This field is not intended to be read by
the client, but by the ContentResolver. The client will call <code>{@link
android.content.ContentResolver#openInputStream ContentResolver.openInputStream()}</code>
on the user-facing field holding the URI for the item. The ContentResolver
will request the "{@code _data}" field for that record, and because
it has higher permissions than a client, it should be able to access
that file directly and return a read wrapper for the file to the client.</p></li>
</ul>
<p>
For an example of a private content provider implementation, see the
NodePadProvider class in the Notepad sample application that ships with the SDK.
</p>
<h3>Declaring the content provider</h3>
<p>
To let the Android system know about the content provider you've developed,
declare it with a {@code <provider>} element in the application's
AndroidManifest.xml file. Content providers that are not declared in the
manifest are not visible to the Android system
</p>
<p>
The {@code name} attribute is the fully qualified name of the ContentProvider
subclass. The {@code authorities} attribute is the authority part of the
{@code content:} URI that identifies the provider.
For example if the ContentProvider subclass is AutoInfoProvider, the
{@code <provider>} element might look like this:
</p>
<pre>
<provider name="com.example.autos.AutoInfoProvider"
authorities="com.example.autos.autoinfoprovider"
. . . />
</provider>
</pre>
<p>
Note that the {@code authorities} attribute omits the path part of a
{@code content:} URI. For example, if AutoInfoProvider controlled subtables
for different types of autos or different manufacturers,
</p>
<p style="margin-left: 2em">{@code content://com.example.autos.autoinfoprovider/honda}
<br/>{@code content://com.example.autos.autoinfoprovider/gm/compact}
<br/>{@code content://com.example.autos.autoinfoprovider/gm/suv}</p>
<p>
those paths would not be declared in the manifest. The authority is what
identifies the provider, not the path; your provider can interpret the path
part of the URI in any way you choose.
</p>
<p>
Other {@code <provider>} attributes can set permissions to read and
write data, provide for an icon and text that can be displayed to users,
enable and disable the provider, and so on. Set the {@code multiprocess}
attribute to "{@code true}" if data does not need to be synchronized between
multiple running versions of the content provider. This permits an instance
of the provider to be created in each client process, eliminating the need
to perform IPC.
</p>
<h2><a name="urisum"></a>Content URI Summary</h2>
<p>
Here is a recap of the important parts of a content URI:
</p>
<p>
<img src="{@docRoot}images/content_uri.png" alt="Elements of a content URI"
height="80" width="528">
</p>
<ol type="A">
<li>Standard prefix indicating that the data is controlled by a
content provider. It's never modified.</li>
<li><p>The authority part of the URI; it identifies the content provider.
For third-party applications, this should be a fully-qualified class name
(reduced to lowercase) to ensure uniqueness. The authority is declared in
the {@code <provider>} element's {@code authorities} attribute:</p>
<pre><provider name=".TransportationProvider"
authorities="com.example.transportationprovider"
. . . ></pre></li>
<li><p>The path that the content provider uses to determine what kind of data is
being requested. This can be zero or more segments long. If the content provider
exposes only one type of data (only trains, for example), it can be absent.
If the provider exposes several types, including subtypes, it can be several
segments long — for example, "{@code land/bus}", "{@code land/train}",
"{@code sea/ship}", and "{@code sea/submarine}" to give four possibilities.</p></li>
<li><p>The ID of the specific record being requested, if any. This is the
{@code _ID} value of the requested record. If the request is not limited to
a single record, this segment and the trailing slash are omitted:</p>
<p style="margin-left: 2em">{@code content://com.example.transportationprovider/trains}</p>
</li>
</ol>
|