From a2a46f629446af0935e8ebbbd7cdb55e395f79f3 Mon Sep 17 00:00:00 2001
From: Joe Malin
+ A content provider manages access to a central repository of data. The provider and
+ is part of an Android application, which often provides its own UI for working with
+ the data. However, content providers are primarily intended to be used by other
+ applications, which access the provider using a provider client object. Together, providers
+ and provider clients offer a consistent, standard interface to data that also handles
+ inter-process communication and secure data access.
+
+ This topic describes the basics of the following:
+
+ A content provider presents data to external applications as one or more tables that are
+ similar to the tables found in a relational database. A row represents an instance of some type
+ of data the provider collects, and each row in the column represents an individual piece of
+ data collected for an instance.
+
+ For example, one of the built-in providers in the Android platform is the user dictionary, which
+ stores the spellings of non-standard words that the user wants to keep. Table 1 illustrates what
+ the data might look like in this provider's table:
+
+ In table 1, each row represents an instance of a word that might not be
+ found in a standard dictionary. Each column represents some data for that word, such as the
+ locale in which it was first encountered. The column headers are column names that are stored in
+ the provider. To refer to a row's locale, you refer to its
+ Note: A provider isn't required to have a primary key, and it isn't required
+ to use
+ An application accesses the data from a content provider with
+ a {@link android.content.ContentResolver} client object. This object has methods that call
+ identically-named methods in the provider object, an instance of one of the concrete
+ subclasses of {@link android.content.ContentProvider}. The
+ {@link android.content.ContentResolver} methods provide the basic
+ "CRUD" (create, retrieve, update, and delete) functions of persistent storage.
+
+ The {@link android.content.ContentResolver} object in the client application's
+ process and the {@link android.content.ContentProvider} object in the application that owns
+ the provider automatically handle inter-process communication.
+ {@link android.content.ContentProvider} also acts as an abstraction layer between its
+ repository of data and the external appearance of data as tables.
+
+ Note: To access a provider, your application usually has to request specific
+ permissions in its manifest file. This is described in more detail in the section
+ Content Provider Permissions
+
+ For example, to get a list of the words and their locales from the User Dictionary Provider,
+ you call {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+ ContentResolver.query()}.
+ The {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+ query()} method calls the
+ {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+ ContentProvider.query()} method defined by the User Dictionary Provider. The following lines
+ of code show a
+ {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+ ContentResolver.query()} call:
+
+
+ Table 2 shows how the arguments to
+ {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+ query(Uri,projection,selection,selectionArgs,sortOrder)} match an SQL SELECT statement:
+
+ A content URI is a URI that identifies data in a provider. Content URIs
+ include the symbolic name of the entire provider (its authority) and a
+ name that points to a table (a path). When you call
+ a client method to access a table in a provider, the content URI for the table is one of
+ the arguments.
+
+ In the preceding lines of code, the constant
+ {@link android.provider.UserDictionary.Words#CONTENT_URI} contains the content URI of
+ the user dictionary's "words" table. The {@link android.content.ContentResolver}
+ object parses out the URI's authority, and uses it to "resolve" the provider by
+ comparing the authority to a system table of known providers. The
+ {@link android.content.ContentResolver} can then dispatch the query arguments to the correct
+ provider.
+
+ The {@link android.content.ContentProvider} uses the path part of the content URI to choose the
+ table to access. A provider usually has a path for each table it exposes.
+
+ In the previous lines of code, the full URI for the "words" table is:
+
+ where the
+ Many providers allow you to access a single row in a table by appending an ID value
+ to the end of the URI. For example, to retrieve a row whose
+ You often use id values when you've retrieved a set of rows and then want to update or delete
+ one of them.
+
+ Note: The {@link android.net.Uri} and {@link android.net.Uri.Builder} classes
+ contain convenience methods for constructing well-formed Uri objects from strings. The
+ {@link android.content.ContentUris} contains convenience methods for appending id values to
+ a URI. The previous snippet uses {@link android.content.ContentUris#withAppendedId(Uri, long)
+ withAppendedId()} to append an id to the UserDictionary content URI.
+
+ This section describes how to retrieve data from a provider, using the User Dictionary Provider
+ as an example.
+
+ For the sake of clarity, the code snippets in this section call
+ {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+ ContentResolver.query()} on the "UI thread"". In actual code, however, you should
+ do queries asynchronously on a separate thread. One way to do this is to use the
+ {@link android.content.CursorLoader} class, which is described
+ in more detail in the
+ Loaders guide. Also, the lines of code are snippets only; they don't show a complete
+ application.
+
+ To retrieve data from a provider, follow these basic steps:
+
+ To retrieve data from a provider, your application needs "read access permission" for the
+ provider. You can't request this permission at run-time; instead, you have to specify that
+ you need this permission in your manifest, using the
+
+ To find the exact name of the read access permission for the provider you're using, as well
+ as the names for other access permissions used by the provider, look in the provider's
+ documentation.
+
+ The role of permissions in accessing providers is described in more detail in the section
+ Content Provider Permissions.
+
+ The User Dictionary Provider defines the permission
+
+ The next step in retrieving data a provider is to construct a query. This first snippet
+ defines some variables for accessing the User Dictionary Provider:
+
+ The next snippet shows how to use
+ {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+ ContentResolver.query()}, using the User Dictionary Provider as an example.
+ A provider client query is similar to an SQL query, and it contains a set of columns to return,
+ a set of selection criteria, and a sort order.
+
+ The set of columns that the query should return is called a projection
+ (the variable
+ The expression that specifies the rows to retrieve is split into a selection clause and
+ selection arguments. The selection clause is a combination of logical and Boolean expressions,
+ column names, and values (the variable
+ In the next snippet, if the user doesn't enter a word, the selection clause is set to
+
+ This query is analogous to the SQL statement:
+
+ In this SQL statement, the actual column names are used instead of contract class constants.
+
+ If the data managed by the content provider is in an SQL database, including external untrusted
+ data into raw SQL statements can lead to SQL injection.
+
+ Consider this selection clause:
+
+ If you do this, you're allowing the user to concatenate malicious SQL onto your SQL statement.
+ For example, the user could enter "nothing; DROP TABLE *;" for
+ To avoid this problem, use a selection clause that uses
+ Set up the array of selection arguments like this:
+
+ Put a value in the selection arguments array like this:
+
+ A selection clause that uses
+ The {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+ ContentResolver.query()} client method always returns a {@link android.database.Cursor}
+ containing the columns specified by the query's projection for the rows that match the query's
+ selection criteria. A {@link android.database.Cursor} object provides random read access to the
+ rows and columns it contains. Using {@link android.database.Cursor} methods,
+ you can iterate over the rows in the results, determine the data type of each column, get the
+ data out of a column, and examine other properties of the results. Some
+ {@link android.database.Cursor} implementations automatically update the object when the
+ provider's data changes, or trigger methods in an observer object when the
+ {@link android.database.Cursor} changes, or both.
+
+ Note: A provider may restrict access to columns based on the nature of the
+ object making the query. For example, the Contacts Provider restricts access for some columns to
+ sync adapters, so it won't return them to an activity or service.
+
+ If no rows match the selection criteria, the provider
+ returns a {@link android.database.Cursor} object for which
+ {@link android.database.Cursor#getCount() Cursor.getCount()} is 0 (an empty cursor).
+
+ If an internal error occurs, the results of the query depend on the particular provider. It may
+ choose to return
+ Since a {@link android.database.Cursor} is a "list" of rows, a good way to display the
+ contents of a {@link android.database.Cursor} is to link it to a {@link android.widget.ListView}
+ via a {@link android.widget.SimpleCursorAdapter}.
+
+ The following snippet continues the code from the previous snippet. It creates a
+ {@link android.widget.SimpleCursorAdapter} object containing the {@link android.database.Cursor}
+ retrieved by the query, and sets this object to be the adapter for a
+ {@link android.widget.ListView}:
+
+ Note: To back a {@link android.widget.ListView} with a
+ {@link android.database.Cursor}, the cursor must contain a column named
+ Rather than simply displaying query results, you can use them for other tasks. For
+ example, you can retrieve spellings from the user dictionary and then look them up in
+ other providers. To do this, you iterate over the rows in the {@link android.database.Cursor}:
+
+ {@link android.database.Cursor} implementations contain several "get" methods for
+ retrieving different types of data from the object. For example, the previous snippet
+ uses {@link android.database.Cursor#getString(int) getString()}. They also have a
+ {@link android.database.Cursor#getType(int) getType()} method that returns a value indicating
+ the data type of the column.
+
+ A provider's application can specify permissions that other applications must have in order to
+ access the provider's data. These permissions ensure that the user knows what data
+ an application will try to access. Based on the provider's requirements, other applications
+ request the permissions they need in order to access the provider. End users see the requested
+ permissions when they install the application.
+
+ If a provider's application doesn't specify any permissions, then other applications have no
+ access to the provider's data. However, components in the provider's application always have
+ full read and write access, regardless of the specified permissions.
+
+ As noted previously, the User Dictionary Provider requires the
+
+ To get the permissions needed to access a provider, an application requests them with a
+
+ The following
+
+ The impact of permissions on provider access is explained in more detail in the
+ Security and Permissions guide.
+
+ In the same way that you retrieve data from a provider, you also use the interaction between
+ a provider client and the provider's {@link android.content.ContentProvider} to modify data.
+ You call a method of {@link android.content.ContentResolver} with arguments that are passed to
+ the corresponding method of {@link android.content.ContentProvider}. The provider and provider
+ client automatically handle security and inter-process communication.
+
+ To insert data into a provider, you call the
+ {@link android.content.ContentResolver#insert(Uri,ContentValues) ContentResolver.insert()}
+ method. This method inserts a new row into the provider and returns a content URI for that row.
+ This snippet shows how to insert a new word into the User Dictionary Provider:
+
+ The data for the new row goes into a single {@link android.content.ContentValues} object, which
+ is similar in form to a one-row cursor. The columns in this object don't need to have the
+ same data type, and if you don't want to specify a value at all, you can set a column
+ to
+ The snippet doesn't add the
+ The content URI returned in
+ The
+ To get the value of
+ To update a row, you use a {@link android.content.ContentValues} object with the updated
+ values just as you do with an insertion, and selection criteria just as you do with a query.
+ The client method you use is
+ {@link android.content.ContentResolver#update(Uri, ContentValues, String, String[])
+ ContentResolver.update()}. You only need to add values to the
+ {@link android.content.ContentValues} object for columns you're updating. If you want to clear
+ the contents of a column, set the value to
+ The following snippet changes all the rows whose locale has the language "en" to a
+ have a locale of
+ You should also sanitize user input when you call
+ {@link android.content.ContentResolver#update(Uri, ContentValues, String, String[])
+ ContentResolver.update()}. To learn more about this, read the section
+ Protecting against malicious input.
+
+ Deleting rows is similar to retrieving row data: you specify selection criteria for the rows
+ you want to delete and the client method returns the number of deleted rows.
+ The following snippet deletes rows whose appid matches "user". The method returns the
+ number of deleted rows.
+
+ You should also sanitize user input when you call
+ {@link android.content.ContentResolver#delete(Uri, String, String[])
+ ContentResolver.delete()}. To learn more about this, read the section
+ Protecting against malicious input.
+
+ Content providers can offer many different data types. The User Dictionary Provider offers only
+ text, but providers can also offer the following formats:
+
+ Another data type that providers often use is Binary Large OBject (BLOB) implemented as a
+ 64KB byte array. You can see the available data types by looking at the
+ {@link android.database.Cursor} class "get" methods.
+
+ The data type for each column in a provider is usually listed in its documentation.
+ The data types for the User Dictionary Provider are listed in the reference documentation
+ for its contract class {@link android.provider.UserDictionary.Words} (contract classes are
+ described in the section Contract Classes).
+ You can also determine the data type by calling {@link android.database.Cursor#getType(int)
+ Cursor.getType()}.
+
+ Providers also maintain MIME data type information for each content URI they define. You can
+ use the MIME type information to find out if your application can handle data that the
+ provider offers, or to choose a type of handling based on the MIME type. You usually need the
+ MIME type when you are working with a provider that contains complex
+ data structures or files. For example, the {@link android.provider.ContactsContract.Data}
+ table in the Contacts Provider uses MIME types to label the type of contact data stored in each
+ row. To get the MIME type corresponding to a content URI, call
+ {@link android.content.ContentResolver#getType(Uri) ContentResolver.getType()}.
+
+ The section MIME Type Reference describes the
+ syntax of both standard and custom MIME types.
+
+ Three alternative forms of provider access are important in application development:
+
+ Batch access and modification via intents are described in the following sections.
+
+ Batch access to a provider is useful for inserting a large number of rows, or for inserting
+ rows in multiple tables in the same method call, or in general for performing a set of
+ operations across process boundaries as a transaction (an atomic operation).
+
+ To access a provider in "batch mode",
+ you create an array of {@link android.content.ContentProviderOperation} objects and then
+ dispatch them to a content provider with
+ {@link android.content.ContentResolver#applyBatch(String, ArrayList)
+ ContentResolver.applyBatch()}. You pass the content provider's authority to this
+ method, rather than a particular content URI, which allows each
+ {@link android.content.ContentProviderOperation} object in the array to work against a
+ different table. A call to {@link android.content.ContentResolver#applyBatch(String, ArrayList)
+ ContentResolver.applyBatch()} returns an array of results.
+
+ The description of the {@link android.provider.ContactsContract.RawContacts} contract class
+ includes a code snippet that demonstrates batch insertion. The
+ Contact Manager
+ sample application contains an example of batch access in its
+ If your application does have access permissions, you still may want to use an
+ intent to display data in another application. For example, the Calendar application accepts an
+ {@link android.content.Intent#ACTION_VIEW} intent, which displays a particular date or event.
+ This allows you to display calendar information without having to create your own UI.
+ To learn more about this feature, see the
+ Calendar Provider guide.
+
+ The application to which you send the intent doesn't have to be the application
+ associated with the provider. For example, you can retrieve a contact from the
+ Contact Provider, then send an {@link android.content.Intent#ACTION_VIEW} intent
+ containing the content URI for the contact's image to an image viewer.
+
+ Intents can provide indirect access to a content provider. You allow the user to access
+ data in a provider even if your application doesn't have access permissions, either by
+ getting a result intent back from an application that has permissions, or by activating an
+ application that has permissions and letting the user do work in it.
+
+ You can access data in a content provider, even if you don't have the proper access
+ permissions, by sending an intent to an application that does have the permissions and
+ receiving back a result intent containing "URI" permissions.
+ These are permissions for a specific content URI that last until the activity that receives
+ them is finished. The application that has permanent permissions grants temporary
+ permissions by setting a flag in the result intent:
+
+ Note: These flags don't give general read or write access to the provider
+ whose authority is contained in the content URI. The access is only for the URI itself.
+
+ A provider defines URI permissions for content URIs in its manifest, using the
+
+ For example, you can retrieve data for a contact in the Contacts Provider, even if you don't
+ have the {@link android.Manifest.permission#READ_CONTACTS} permission. You might want to do
+ this in an application that sends e-greetings to a contact on his or her birthday. Instead of
+ requesting {@link android.Manifest.permission#READ_CONTACTS}, which gives you access to all of
+ the user's contacts and all of their information, you prefer to let the user control which
+ contacts are used by your application. To do this, you use the following process:
+
+ A simple way to allow the user to modify data to which you don't have access permissions is to
+ activate an application that has permissions and let the user do the work there.
+
+ For example, the Calendar application accepts an
+ {@link android.content.Intent#ACTION_INSERT} intent, which allows you to activate the
+ application's insert UI. You can pass "extras" data in this intent, which the application
+ uses to pre-populate the UI. Because recurring events have a complex syntax, the preferred
+ way of inserting events into the Calendar Provider is to activate the Calendar app with an
+ {@link android.content.Intent#ACTION_INSERT} and then let the user insert the event there.
+
+ A contract class defines constants that help applications work with the content URIs, column
+ names, intent actions, and other features of a content provider. Contract classes are not
+ included automatically with a provider; the provider's developer has to define them and then
+ make them available to other developers. Many of the providers included with the Android
+ platform have corresponding contract classes in the package {@link android.provider}.
+
+ For example, the User Dictionary Provider has a contract class
+ {@link android.provider.UserDictionary} containing content URI and column name constants. The
+ content URI for the "words" table is defined in the constant
+ {@link android.provider.UserDictionary.Words#CONTENT_URI UserDictionary.Words.CONTENT_URI}.
+ The {@link android.provider.UserDictionary.Words} class also contains column name constants,
+ which are used in the example snippets in this guide. For example, a query projection can be
+ defined as:
+
+ Another contract class is {@link android.provider.ContactsContract} for the Contacts Provider.
+ The reference documentation for this class includes example code snippets. One of its
+ subclasses, {@link android.provider.ContactsContract.Intents.Insert}, is a contract
+ class that contains constants for intents and intent data.
+
+ Content providers can return standard MIME media types, or custom MIME type strings, or both.
+
+ MIME types have the format
+
+ For example, the well-known MIME type
+ Custom MIME type strings, also called "vendor-specific" MIME types, have more
+ complex type and subtype values. The type value is always
+
+ for multiple rows, or
+
+ for a single row.
+
+ The subtype is provider-specific. The Android built-in providers usually have a simple
+ subtype. For example, the when the Contacts application creates a row for a telephone number,
+ it sets the following MIME type in the row:
+
+ Notice that the subtype value is simply
+ Other provider developers may create their own pattern of subtypes based on the provider's
+ authority and table names. For example, consider a provider that contains train timetables.
+ The provider's authority is
+
+ for table Line1, the provider returns the MIME type
+
+ In response to the content URI
+
+ for row 5 in table Line2, the provider returns the MIME type
+
+ Most content providers define contract class constants for the MIME types they use. The
+ Contacts Provider contract class {@link android.provider.ContactsContract.RawContacts},
+ for example, defines the constant
+ {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} for the MIME type of
+ a single raw contact row.
+
+ Content URIs for single rows are described in the section
+ Content URIs.
+
+ A content provider manages access to a central repository of data. You implement a
+ provider as one or more classes in an Android application, along with elements in
+ the manifest file. One of your classes implements a subclass
+ {@link android.content.ContentProvider}, which is the interface between your provider and
+ other applications. Although content providers are meant to make data available to other
+ applications, you may of course have activities in your application that allow the user
+ to query and modify the data managed by your provider.
+
+ The rest of this topic is a basic list of steps for building a content provider and a list
+ of APIs to use.
+
+ Before you start building a provider, do the following:
+
+ You don't need a provider to use an SQLite database if the use is entirely within
+ your own application.
+
+ Next, follow these steps to build your provider:
+
+ A content provider is the interface to data saved in a structured format. Before you create
+ the interface, you must decide how to store the data. You can store the data in any form you
+ like, and then design the interface to read and write the data as necessary.
+
+ These are some of the data storage technologies that are available in Android:
+
+ Remember that you don't have to use a database to implement your repository. A provider
+ appears externally as a set of tables, similar to a relational database, but this is
+ not a requirement for the provider's internal implementation.
+
+ Here are some tips for designing your provider's data structure:
+
+ You can also use a BLOB to implement a schema-independent table. In
+ this type of table, you define a primary key column, a MIME type column, and one or
+ more generic columns as BLOB. The meaning of the data in the BLOB columns is indicated
+ by the value in the MIME type column. This allows you to store different row types in
+ the same table. The Contacts Provider's "data" table
+ {@link android.provider.ContactsContract.Data} is an example of a schema-independent
+ table.
+
+ A content URI is a URI that identifies data in a provider. Content URIs include
+ the symbolic name of the entire provider (its authority) and a
+ name that points to a table or file (a path). The optional id part points to
+ an individual row in a table. Every data access method of
+ {@link android.content.ContentProvider} has a content URI as an argument; this allows you to
+ determine the table, row, or file to access.
+
+ The basics of content URIs are described in the topic
+
+ Content Provider Basics.
+
+ A provider usually has a single authority, which serves as its Android-internal name. To
+ avoid conflicts with other providers, you should use Internet domain ownership (in reverse)
+ as the basis of your provider authority. Because this recommendation is also true for Android
+ package names, you can define your provider authority as an extension of the name
+ of the package containing the provider. For example, if your Android package name is
+
+ Developers usually create content URIs from the authority by appending paths that point to
+ individual tables. For example, if you have two tables table1 and
+ table2, you combine the authority from the previous example to yield the
+ content URIs
+
+ By convention, providers offer access to a single row in a table by accepting a content URI
+ with an ID value for the row at the end of the URI. Also by convention, providers match the
+ ID value to the table's
+ This convention facilitates a common design pattern for apps accessing a provider. The app
+ does a query against the provider and displays the resulting {@link android.database.Cursor}
+ in a {@link android.widget.ListView} using a {@link android.widget.CursorAdapter}.
+ The definition of {@link android.widget.CursorAdapter} requires one of the columns in the
+ {@link android.database.Cursor} to be
+ The user then picks one of the displayed rows from the UI in order to look at or modify the
+ data. The app gets the corresponding row from the {@link android.database.Cursor} backing the
+ {@link android.widget.ListView}, gets the
+ To help you choose which action to take for an incoming content URI, the provider API includes
+ the convenience class {@link android.content.UriMatcher}, which maps content URI "patterns" to
+ integer values. You can use the integer values in a
+ A content URI pattern matches content URIs using wildcard characters:
+
+ As an example of designing and coding content URI handling, consider a provider with the
+ authority
+ The provider also recognizes these content URIs if they have a row ID appended to them, as
+ for example
+ The following content URI patterns would be possible:
+
+ The following code snippet shows how the methods in {@link android.content.UriMatcher} work.
+ This code handles URIs for an entire table differently from URIs for a
+ single row, by using the content URI pattern
+
+ The method {@link android.content.UriMatcher#addURI(String, String, int) addURI()} maps an
+ authority and path to an integer value. The method android.content.UriMatcher#match(Uri)
+ match()} returns the integer value for a URI. A
+ Another class, {@link android.content.ContentUris}, provides convenience methods for working
+ with the
+ The {@link android.content.ContentProvider} instance manages access
+ to a structured set of data by handling requests from other applications. All forms
+ of access eventually call {@link android.content.ContentResolver}, which then calls a concrete
+ method of {@link android.content.ContentProvider} to get access.
+
+ The abstract class {@link android.content.ContentProvider} defines six abstract methods that
+ you must implement as part of your own concrete subclass. All of these methods except
+ {@link android.content.ContentProvider#onCreate() onCreate()} are called by a client application
+ that is attempting to access your content provider:
+
+ Notice that these methods have the same signature as the identically-named
+ {@link android.content.ContentResolver} methods.
+
+ Your implementation of these methods should account for the following:
+
+ The
+ {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+ ContentProvider.query()} method must return a {@link android.database.Cursor} object, or if it
+ fails, throw an {@link java.lang.Exception}. If you are using an SQLite database as your data
+ storage, you can simply return the {@link android.database.Cursor} returned by one of the
+
+ If you aren't using an SQLite database as your data storage, use one of the concrete subclasses
+ of {@link android.database.Cursor}. For example, the {@link android.database.MatrixCursor} class
+ implements a cursor in which each row is an array of {@link java.lang.Object}. With this class,
+ use {@link android.database.MatrixCursor#addRow(Object[]) addRow()} to add a new row.
+
+ Remember that the Android system must be able to communicate the {@link java.lang.Exception}
+ across process boundaries. Android can do this for the following exceptions that may be useful
+ in handling query errors:
+
+ The {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} method adds a
+ new row to the appropriate table, using the values in the {@link android.content.ContentValues}
+ argument. If a column name is not in the {@link android.content.ContentValues} argument, you
+ may want to provide a default value for it either in your provider code or in your database
+ schema.
+
+ This method should return the content URI for the new row. To construct this, append the new
+ row's
+ The {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} method
+ does not have to physically delete rows from your data storage. If you are using a sync adapter
+ with your provider, you should consider marking a deleted row
+ with a "delete" flag rather than removing the row entirely. The sync adapter can
+ check for deleted rows and remove them from the server before deleting them from the provider.
+
+ The {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])
+ update()} method takes the same {@link android.content.ContentValues} argument used by
+ {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}, and the
+ same
+ The Android system calls {@link android.content.ContentProvider#onCreate()
+ onCreate()} when it starts up the provider. You should perform only fast-running initialization
+ tasks in this method, and defer database creation and data loading until the provider actually
+ receives a request for the data. If you do lengthy tasks in
+ {@link android.content.ContentProvider#onCreate() onCreate()}, you will slow down your
+ provider's startup. In turn, this will slow down the response from the provider to other
+ applications.
+
+ For example, if you are using an SQLite database you can create
+ a new {@link android.database.sqlite.SQLiteOpenHelper} object in
+ {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()},
+ and then create the SQL tables the first time you open the database. To facilitate this, the
+ first time you call {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase
+ getWritableDatabase()}, it automatically calls the
+ {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
+ SQLiteOpenHelper.onCreate()} method.
+
+ The following two snippets demonstrate the interaction between
+ {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} and
+ {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
+ SQLiteOpenHelper.onCreate()}. The first snippet is the implementation of
+ {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()}:
+
+ The next snippet is the implementation of
+ {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
+ SQLiteOpenHelper.onCreate()}, including a helper class:
+
+ The {@link android.content.ContentProvider} class has two methods for returning MIME types:
+
+ The {@link android.content.ContentProvider#getType(Uri) getType()} method returns a
+ {@link java.lang.String} in MIME format that describes the type of data returned by the content
+ URI argument. The {@link android.net.Uri} argument can be a pattern rather than a specific URI;
+ in this case, you should return the type of data associated with content URIs that match the
+ pattern.
+
+ For common types of data such as as text, HTML, or JPEG,
+ {@link android.content.ContentProvider#getType(Uri) getType()} should return the standard
+ MIME type for that data. A full list of these standard types is available on the
+ IANA MIME Media Types
+ website.
+
+ For content URIs that point to a row or rows of table data,
+ {@link android.content.ContentProvider#getType(Uri) getType()} should return
+ a MIME type in Android's vendor-specific MIME format:
+
+ You supply the
+ For example, if a provider's authority is
+
+ For a single row of
+ If your provider offers files, implement
+ {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}.
+ The method returns a {@link java.lang.String} array of MIME types for the files your provider
+ can return for a given content URI. You should filter the MIME types you offer by the MIME type
+ filter argument, so that you return only those MIME types that the client wants to handle.
+
+ For example, consider a provider that offers photo images as files in
+ If the app is only interested in
+ If your provider doesn't offer any of the MIME types requested in the filter string,
+ {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}
+ should return
+ A contract class is a
+ A contract class also helps developers because it usually has mnemonic names for its constants,
+ so developers are less likely to use incorrect values for column names or URIs. Since it's a
+ class, it can contain Javadoc documentation. Integrated development environments such as
+ Eclipse can auto-complete constant names from the contract class and display Javadoc for the
+ constants.
+
+ Developers can't access the contract class's class file from your application, but they can
+ statically compile it into their application from a
+ The {@link android.provider.ContactsContract} class and its nested classes are examples of
+ contract classes.
+
+ Permissions and access for all aspects of the Android system are described in detail in the
+ topic Security and Permissions.
+ The topic Data Storage also
+ described the security and permissions in effect for various types of storage.
+ In brief, the important points are:
+
+ If you want to use content provider permissions to control access to your data, then you should
+ store your data in internal files, SQLite databases, or the "cloud" (for example,
+ on a remote server), and you should keep files and databases private to your application.
+
+ All applications can read from or write to your provider, even if the underlying data is
+ private, because by default your provider does not have permissions set. To change this,
+ set permissions for your provider in your manifest file, using attributes or child
+ elements of the
+ You define permissions for your provider with one or more
+
+ The following list describes the scope of provider permissions, starting with the
+ permissions that apply to the entire provider and then becoming more fine-grained.
+ More fine-grained permissions take precedence over ones with larger scope:
+
+ Consider the permissions you need to implement an email provider and app, when you
+ want to allow an outside image viewer application to display photo attachments from your
+ provider. To give the image viewer the necessary access without requiring permissions,
+ set up temporary permissions for content URIs for photos. Design your email app so
+ that when the user wants to display a photo, the app sends an intent containing the
+ photo's content URI and permission flags to the image viewer. The image viewer can
+ then query your email provider to retrieve the photo, even though the viewer doesn't
+ have the normal read permission for your provider.
+
+ To turn on temporary permissions, either set the
+
+ The attribute's value determines how much of your provider is made accessible.
+ If the attribute is set to
+ If this flag is set to
+ To delegate temporary access to an application, an intent must contain
+ the {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} or the
+ {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} flags, or both. These
+ are set with the {@link android.content.Intent#setFlags(int) setFlags()} method.
+
+ If the
+ Like {@link android.app.Activity} and {@link android.app.Service} components,
+ a subclass of {@link android.content.ContentProvider}
+ must be defined in the manifest file for its application, using the
+
+ Permissions and their corresponding attributes are described in more
+ detail in the section
+ Implementing Content Provider Permissions.
+
+ The attributes are fully documented in the dev guide topic for the
+
+ The attributes are fully documented in the dev guide topic for the
+
+ Applications can access a content provider indirectly with an {@link android.content.Intent}.
+ The application does not call any of the methods of {@link android.content.ContentResolver} or
+ {@link android.content.ContentProvider}. Instead, it sends an intent that starts an activity,
+ which is often part of the provider's own application. The destination activity is in charge of
+ retrieving and displaying the data in its UI. Depending on the action in the intent, the
+ destination activity may also prompt the user to make modifications to the provider's data.
+ An intent may also contain "extras" data that the destination activity displays
+ in the UI; the user then has the option of changing this data before using it to modify the
+ data in the provider.
+
+
+
+ You may want to use intent access to help ensure data integrity. Your provider may depend
+ on having data inserted, updated, and deleted according to strictly defined business logic. If
+ this is the case, allowing other applications to directly modify your data may lead to
+ invalid data. If you want developers to use intent access, be sure to document it thoroughly.
+ Explain to them why intent access using your own application's UI is better than trying to
+ modify the data with their code.
+
+ Handling an incoming intent that wishes to modify your provider's data is no different from
+ handling other intents. You can learn more about using intents by reading the topic
+ Intents and Intent Filters.
+
-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.
-
-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).
- Note: Android 4.0 introduces the Calendar
-Provider. For more information, see Calendar
-Provider.
-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.
-
-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.
-
-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.
-
-It's an interface that clients use indirectly, most generally through
-{@link android.content.ContentResolver} objects. You get a ContentResolver
-by calling
-You can then use the ContentResolver's methods to interact with whatever
-content providers you're interested in.
-
-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.
-
-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:
-
-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.
-
-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.)
-
-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.
-
-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:
-
- {@code android.provider.Contacts.Phones.CONTENT_URI}
-
-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.
-
-You need three pieces of information to query a content provider:
-
-If you're querying a particular record, you also need the ID for that record.
-
-To query a content provider, you can use either the
-
-The first argument to either
-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:
- {@code content://. . . ./23}
-There are some helper methods, particularly
-
-The other arguments to the 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). Selection arguments. 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.
-Let's look at an example query to retrieve a list of contact names and their
-primary phone numbers:
-
-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.
-
-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.
-
-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.
-
-Here is an example result set for the query in the previous section:
-
-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.
-
-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
-The following snippet demonstrates reading names and phone numbers from
-the query illustrated earlier:
-
-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
-
-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
-
-Data kept by a content provider can be modified by:
-
-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.
-
-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
-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.
-
-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:
-
-You can place small amounts of binary data into a table by calling
-the version of
-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:
-
-To batch update a group of records (for example, to change "NY" to "New York"
-in all fields), call the
-To delete a single record, call {
-To delete multiple rows, call
-To create a content provider, you must:
- Extend the {@link android.content.ContentProvider} class to provide
-access to the data. Declare the content provider in the manifest file for your
-application (AndroidManifest.xml).
-The following sections have notes on the last two of these tasks.
-
-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:
- {@code query()}
-
-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.
-
-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.
-
-As a courtesy, you might also want to call
-Beyond defining the subclass itself, there are other steps you should take
-to simplify the work of clients and make the class more accessible:
-
-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:
- {@code content://com.example.codelab.transportationprovider/train}
-
-For an overview of {@code content:} URIs, see the Content URI
-Summary at the end of this document.
- 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.
-
-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:
- {@code INTEGER PRIMARY KEY AUTOINCREMENT}
-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.
- Carefully document the data type of each column. Clients need this
-information to read the data. If you are handling a new data type, you must define a new MIME type
-to return in your implementation of For a single record: {@code vnd.android.cursor.item/vnd.yourcompanyname.contenttype} For example, a request for train record 122, like this URI, {@code content://com.example.transportationprovider/trains/122} might return this MIME type: {@code vnd.android.cursor.item/vnd.example.rail} For multiple records: {@code vnd.android.cursor.dir/vnd.yourcompanyname.contenttype} For example, a request for all train records, like the following URI, {@code content://com.example.transportationprovider/trains} might return this MIME type: {@code vnd.android.cursor.dir/vnd.example.rail} 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
-For an example of a private content provider implementation, see the
-NodePadProvider class in the Notepad sample application that ships with the SDK.
-
-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
-
-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:
-
-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,
- {@code content://com.example.autos.autoinfoprovider/honda}
-
-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.
-
-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.
-
-Here is a recap of the important parts of a content URI:
-
-
- 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: 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. 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: {@code content://com.example.transportationprovider/trains}
-
In this document
+
+
+
+
+
+
+
+
+
+
+
+
+ Key classes
+
+
+
+
+Related Samples
+
+
+
+
+See also
+
+
+
+
+
+
+Overview
+
+
+
+
+ word
+ app id
+ frequency
+ locale
+ _ID
+
+
+ mapreduce
+ user1
+ 100
+ en_US
+ 1
+
+
+ precompiler
+ user14
+ 200
+ fr_FR
+ 2
+
+
+ applet
+ user2
+ 225
+ fr_CA
+ 3
+
+
+ const
+ user1
+ 255
+ pt_BR
+ 4
+
+
+int
+ user5
+ 100
+ en_UK
+ 5
+ locale
column. For
+ this provider, the _ID
column serves as a "primary key" column that
+ the provider automatically maintains.
+_ID
as the column name of a primary key if one is present. However,
+ if you want to bind data from a provider to a {@link android.widget.ListView}, one of the
+ column names has to be _ID
. This requirement is explained in more detail in the
+ section Displaying query results.
+Accessing a provider
+
+// Queries the user dictionary and returns results
+mCursor = getContentResolver().query(
+ UserDictionary.Words.CONTENT_URI, // The content URI of the words table
+ mProjection, // The columns to return for each row
+ mSelectionClause // Selection criteria
+ mSelectionArgs, // Selection criteria
+ mSortOrder); // The sort order for the returned rows
+
+
+
+
+
+ query() argument
+ SELECT keyword/parameter
+ Notes
+
+
+
+ Uri
+ FROM table_name
+ Uri
maps to the table in the provider named table_name.
+
+
+ projection
+ col,col,col,...
+
+ projection
is an array of columns that should be included for each row
+ retrieved.
+
+
+
+ selection
+ WHERE col = value
+ selection
specifies the criteria for selecting rows.
+
+
+ selectionArgs
+ (No exact equivalent. Selection arguments replace
+ ?
placeholders in the
+ selection clause.)
+
+
+
+ sortOrder
+ ORDER BY col,col,...
+
+ sortOrder
specifies the order in which rows appear in the returned
+ {@link android.database.Cursor}.
+ Content URIs
+
+content://user_dictionary/words
+
+user_dictionary
string is the provider's authority, and
+ words
string is the table's path. The string
+ content://
(the scheme) is always present,
+ and identifies this as a content URI.
+_ID
is
+ 4
from user dictionary, you can use this content URI:
+
+Uri singleUri = ContentUri.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
+
+Retrieving Data from the Provider
+
+
+Requesting read access permission
+
+ <uses-permission>
element and the exact permission name defined by the
+ provider. When you specify this element in your manifest, you are in effect "requesting" this
+ permission for your application. When users install your application, they implicitly grant
+ this request.
+android.permission.READ_USER_DICTIONARY
in its manifest file, so an
+ application that wants to read from the provider must request this permission.
+Constructing the query
+
+
+// A "projection" defines the columns that will be returned for each row
+String[] mProjection =
+{
+ UserDictionary.Words._ID, // Contract class constant for the _ID column name
+ UserDictionary.Words.WORD, // Contract class constant for the word column name
+ UserDictionary.Words.LOCALE // Contract class constant for the locale column name
+};
+
+// Defines a string to contain the selection clause
+String mSelectionClause = null;
+
+// Initializes an array to contain selection arguments
+String[] mSelectionArgs = {""};
+
+
+mProjection
).
+mSelection
). If you specify the replaceable
+ parameter ?
instead of a value, the query method retrieves the value from the
+ selection arguments array (the variable mSelectionArgs
).
+null
, and the query returns all the words in the provider. If the user enters
+ a word, the selection clause is set to UserDictionary.Words.Word + " = ?"
and
+ the first element of selection arguments array is set to the word the user enters.
+
+/*
+ * This defines a one-element String array to contain the selection argument.
+ */
+String[] mSelectionArgs = {""};
+
+// Gets a word from the UI
+mSearchString = mSearchWord.getText().toString();
+
+// Remember to insert code here to check for invalid or malicious input.
+
+// If the word is the empty string, gets everything
+if (TextUtils.isEmpty(mSearchString)) {
+ // Setting the selection clause to null will return all words
+ mSelectionClause = null;
+ mSelectionArgs[0] = "";
+
+} else {
+ // Constructs a selection clause that matches the word that the user entered.
+ mSelectionClause = " = ?";
+
+ // Moves the user's input string to the selection arguments.
+ mSelectionArgs[0] = mSearchString;
+
+}
+
+// Does a query against the table and returns a Cursor object
+mCursor = getContentResolver().query(
+ UserDictionary.Words.CONTENT_URI, // The content URI of the words table
+ mProjection, // The columns to return for each row
+ mSelectionClause // Either null, or the word the user entered
+ mSelectionArgs, // Either empty, or the string the user entered
+ mSortOrder); // The sort order for the returned rows
+
+// Some providers return null if an error occurs, others throw an exception
+if (null == mCursor) {
+ /*
+ * Insert code here to handle the error. Be sure not to use the cursor! You may want to
+ * call android.util.Log.e() to log this error.
+ *
+ */
+// If the Cursor is empty, the provider found no matches
+} else if (mCursor.getCount() < 1) {
+
+ /*
+ * Insert code here to notify the user that the search was unsuccessful. This isn't necessarily
+ * an error. You may want to offer the user the option to insert a new row, or re-type the
+ * search term.
+ */
+
+} else {
+ // Insert code here to do something with the results
+
+}
+
+
+SELECT _ID, word, frequency, locale FROM words WHERE word = <userinput> ORDER BY word ASC;
+
+Protecting against malicious input
+
+// Constructs a selection clause by concatenating the user's input to the column name
+String mSelectionClause = "var = " + mUserInput;
+
+mUserInput
, which
+ would result in the selection clause var = nothing; DROP TABLE *;
. Since the
+ selection clause is treated as an SQL statement, this might cause the provider to erase all of
+ the tables in the underlying SQLite database (unless the provider is set up to catch
+ SQL injection attempts).
+?
as a replaceable
+ parameter and a separate array of selection arguments. When you do this, the user input
+ is bound directly to the query rather than being interpreted as part of an SQL statement.
+ Because it's not treated as SQL, the user input can't inject malicious SQL. Instead of using
+ concatenation to include the user input, use this selection clause:
+
+// Constructs a selection clause with a replaceable parameter
+String mSelectionClause = "var = ?";
+
+
+// Defines an array to contain the selection arguments
+String[] selectionArgs = {""};
+
+
+// Sets the selection argument to the user's input
+selectionArgs[0] = mUserInput;
+
+?
as a replaceable parameter and an array of
+ selection arguments array are preferred way to specify a selection, even the provider isn't
+ based on an SQL database.
+Displaying query results
+null
, or it may throw an {@link java.lang.Exception}.
+
+// Defines a list of columns to retrieve from the Cursor and load into an output row
+String[] mWordListColumns =
+{
+ UserDictionary.Words.WORD, // Contract class constant containing the word column name
+ UserDictionary.Words.LOCALE // Contract class constant containing the locale column name
+};
+
+// Defines a list of View IDs that will receive the Cursor columns for each row
+int[] mWordListItems = { R.id.dictWord, R.id.locale};
+
+// Creates a new SimpleCursorAdapter
+mCursorAdapter = new SimpleCursorAdapter(
+ getApplicationContext(), // The application's Context object
+ R.layout.wordlistrow, // A layout in XML for one row in the ListView
+ mCursor, // The result from the query
+ mWordListColumns, // A string array of column names in the cursor
+ mWordListItems, // An integer array of view IDs in the row layout
+ 0); // Flags (usually none are needed)
+
+// Sets the adapter for the ListView
+mWordList.setAdapter(mCursorAdapter);
+
+_ID
.
+ Because of this, the query shown previously retrieves the _ID
column for the
+ "words" table, even though the {@link android.widget.ListView} doesn't display it.
+ This restriction also explains why most providers have a _ID
column for each of
+ their tables.
+Getting data from query results
+
+
+// Determine the column index of the column named "word"
+int index = mCursor.getColumnIndex(UserDictionary.Words.WORD);
+
+/*
+ * Only executes if the cursor is valid. The User Dictionary Provider returns null if
+ * an internal error occurs. Other providers may throw an Exception instead of returning null.
+ */
+
+if (mCursor != null) {
+ /*
+ * Moves to the next row in the cursor. Before the first movement in the cursor, the
+ * "row pointer" is -1, and if you try to retrieve data at that position you will get an
+ * exception.
+ */
+ while (mCursor.moveToNext()) {
+
+ // Gets the value from the column.
+ newWord = mCursor.getString(index);
+
+ // Insert code here to process the retrieved word.
+
+ ...
+
+ // end of while loop
+ }
+} else {
+
+ // Insert code here to report an error if the cursor is null or the provider threw an exception.
+}
+
+Content Provider Permissions
+android.permission.READ_USER_DICTIONARY
permission to retrieve data from it.
+ The provider has the separate android.permission.WRITE_USER_DICTIONARY
+ permission for inserting, updating, or deleting data.
+
+ <uses-permission>
element in its manifest file.
+ When the Android Package Manager installs the application, a user must approve all of the
+ permissions the application requests. If the user approves all of them, Package Manager
+ continues the installation; if the user doesn't approve them, Package Manager
+ aborts the installation.
+
+ <uses-permission>
element requests read access to the User Dictionary Provider:
+
+ <uses-permission android:name="android.permission.READ_USER_DICTIONARY">
+
+Inserting, Updating, and Deleting Data
+Inserting data
+
+// Defines a new Uri object that receives the result of the insertion
+Uri mNewUri;
+
+...
+
+// Defines an object to contain the new values to insert
+ContentValues mNewValues = new ContentValues();
+
+/*
+ * Sets the values of each column and inserts the word. The arguments to the "put"
+ * method are "column name" and "value"
+ */
+mNewValues.put(UserDictionary.Words.APP_ID, "example.user");
+mNewValues.put(UserDictionary.Words.LOCALE, "en_US");
+mNewValues.put(UserDictionary.Words.WORD, "insert");
+mNewValues.put(UserDictionary.Words.FREQUENCY, "100");
+
+mNewUri = getContentResolver().insert(
+ UserDictionary.Word.CONTENT_URI, // the user dictionary content URI
+ mNewValues // the values to insert
+);
+
+null
using {@link android.content.ContentValues#putNull(String)
+ ContentValues.putNull()}.
+_ID
column, because this column is maintained
+ automatically. The provider assigns a unique value of _ID
to every row that is
+ added. Providers usually use this value as the table's primary key.
+newUri
identifies the newly-added row, with
+ the following format:
+
+content://user_dictionary/words/<id_value>
+
+<id_value>
is the contents of _ID
for the new row.
+ Most providers can detect this form of content URI automatically and then perform the requested
+ operation on that particular row.
+_ID
from the returned {@link android.net.Uri}, call
+ {@link android.content.ContentUris#parseId(Uri) ContentUris.parseId()}.
+Updating data
+null
.
+null
. The return value is the number of rows that were updated:
+
+// Defines an object to contain the updated values
+ContentValues mUpdateValues = new ContentValues();
+
+// Defines selection criteria for the rows you want to update
+String mSelectionClause = UserDictionary.Words.LOCALE + "LIKE ?";
+String[] mSelectionArgs = {"en_%"};
+
+// Defines a variable to contain the number of updated rows
+int mRowsUpdated = 0;
+
+...
+
+/*
+ * Sets the updated value and updates the selected words.
+ */
+mUpdateValues.putNull(UserDictionary.Words.LOCALE);
+
+mRowsUpdated = getContentResolver().update(
+ UserDictionary.Words.CONTENT_URI, // the user dictionary content URI
+ mUpdateValues // the columns to update
+ mSelectionClause // the column to select on
+ mSelectionArgs // the value to compare to
+);
+
+Deleting data
+
+
+// Defines selection criteria for the rows you want to delete
+String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?";
+String[] mSelectionArgs = {"user"};
+
+// Defines a variable to contain the number of rows deleted
+int mRowsDeleted = 0;
+
+...
+
+// Deletes the words that match the selection criteria
+mRowsDeleted = getContentResolver().delete(
+ UserDictionary.Words.CONTENT_URI, // the user dictionary content URI
+ mSelectionClause // the column to select on
+ mSelectionArgs // the value to compare to
+);
+
+Provider Data Types
+
+
+Alternative Forms of Provider Access
+
+
+Batch access
+ContactAdder.java
+ source file.
+Displaying data using a helper app
+Data access via intents
+Getting access with temporary permissions
+
+
+
+ android:grantUriPermission
+ attribute of the
+ {@code <provider>}
+ element, as well as the
+ {@code
+ <grant-uri-permission>} child element of the
+ {@code <provider>}
+ element. The URI permissions mechanism is explained in more detail in the
+ Security and Permissions guide,
+ in the section "URI Permissions".
+
+
+Using another application
+Contract Classes
+
+String[] mProjection =
+{
+ UserDictionary.Words._ID,
+ UserDictionary.Words.WORD,
+ UserDictionary.Words.LOCALE
+};
+
+MIME Type Reference
+
+type/subtype
+
+text/html
has the text
type and
+ the html
subtype. If the provider returns this type for a URI, it means that a
+ query using that URI will return text containing HTML tags.
+
+vnd.android.cursor.dir
+
+
+vnd.android.cursor.item
+
+
+vnd.android.cursor.item/phone_v2
+
+phone_v2
.
+com.example.trains
, and it contains the tables
+ Line1, Line2, and Line3. In response to the content URI
+
+content://com.example.trains/Line1
+
+
+vnd.android.cursor.dir/vnd.example.line1
+
+
+content://com.example.trains/Line2/5
+
+
+vnd.android.cursor.item/vnd.example.line2
+
+In this document
+
+
+
+
+ Key classes
+
+
+Related Samples
+
+
+See also
+
+
+Before You Start Building
+
+
+
+
+
+
+
+
+
+
+
+ Designing Data Storage
+
+
+
+ Data design considerations
+
+
+
+
+_ID
.
+ Designing Content URIs
+Designing an authority
+com.example.<appname>
, you should give your provider the
+ authority com.example.<appname>.provider
.
+Designing a path structure
+com.example.<appname>.provider/table1
and
+ com.example.<appname>.provider/table2
. Paths aren't
+ limited to a single segment, and there doesn't have to be a table for each level of the path.
+Handling content URI IDs
+_ID
column, and perform the requested access against the
+ row that matches.
+_ID
+_ID
value for this row, appends it to
+ the content URI, and sends the access request to the provider. The provider can then do the
+ query or modification against the exact row the user picked.
+Content URI patterns
+switch
statement that
+ chooses the desired action for the content URI or URIs that match a particular pattern.
+
+
+*
: Matches a string of any valid characters of any length.
+ #
: Matches a string of numeric characters of any length.
+ com.example.app.provider
that recognizes the following content URIs
+ pointing to tables:
+
+
+content://com.example.app.provider/table1
: A table called table1
.
+ content://com.example.app.provider/table2/dataset1
: A table called
+ dataset1
.
+ content://com.example.app.provider/table2/dataset2
: A table called
+ dataset2
.
+ content://com.example.app.provider/table3
: A table called table3
.
+ content://com.example.app.provider/table3/1
for the row identified by
+ 1
in table3
.
+
+
+content://com.example.app.provider/*
+ content://com.example.app.provider/table2/*
:
+ dataset1
+ and dataset2
, but doesn't match content URIs for table1
or
+ table3
.
+ content://com.example.app.provider/table3/#
: Matches a content URI
+ for single rows in table3
, such as
+ content://com.example.app.provider/table3/6
for the row identified by
+ 6
.
+ content://<authority>/<path>
for tables, and
+ content://<authority>/<path>/<id>
for single rows.
+switch
statement
+ chooses between querying the entire table, and querying for a single record:
+
+public class ExampleProvider extends ContentProvider {
+...
+ // Creates a UriMatcher object.
+ private static final UriMatcher sUriMatcher;
+...
+ /*
+ * The calls to addURI() go here, for all of the content URI patterns that the provider
+ * should recognize. For this snippet, only the calls for table 3 are shown.
+ */
+...
+ /*
+ * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used
+ * in the path
+ */
+ sUriMatcher.addURI("com.example.app.provider", "table3", 1);
+
+ /*
+ * Sets the code for a single row to 2. In this case, the "#" wildcard is
+ * used. "content://com.example.app.provider/table3/3" matches, but
+ * "content://com.example.app.provider/table3 doesn't.
+ */
+ sUriMatcher.addURI("com.example.app.provider", "table3/#", 2);
+...
+ // Implements ContentProvider.query()
+ public Cursor query(
+ Uri uri,
+ String[] projection,
+ String selection,
+ String[] selectionArgs,
+ String sortOrder) {
+...
+ /*
+ * Choose the table to query and a sort order based on the code returned for the incoming
+ * URI. Here, too, only the statements for table 3 are shown.
+ */
+ switch (sUriMatcher.match(uri)) {
+
+
+ // If the incoming URI was for all of table3
+ case 1:
+
+ if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";
+ break;
+
+ // If the incoming URI was for a single row
+ case 2:
+
+ /*
+ * Because this URI was for a single row, the _ID value part is
+ * present. Get the last path segment from the URI; this is the _ID value.
+ * Then, append the value to the WHERE clause for the query
+ */
+ selection = selection + "_ID = " uri.getLastPathSegment();
+ break;
+
+ default:
+ ...
+ // If the URI is not recognized, you should do some error handling here.
+ }
+ // call the code to actually do the query
+ }
+
+id
part of content URIs. The classes {@link android.net.Uri} and
+ {@link android.net.Uri.Builder} include convenience methods for parsing existing
+ {@link android.net.Uri} objects and building new ones.
+Implementing the ContentProvider Class
+Required methods
+
+
+
+
+Implementing the query() method
+query()
methods of the {@link android.database.sqlite.SQLiteDatabase} class.
+ If the query does not match any rows, you should return a {@link android.database.Cursor}
+ instance whose {@link android.database.Cursor#getCount()} method returns 0.
+ You should return null
only if an internal error occurred during the query process.
+
+
+Implementing the insert() method
+_ID
(or other primary key) value to the table's content URI, using
+ {@link android.content.ContentUris#withAppendedId(Uri, long) withAppendedId()}.
+Implementing the delete() method
+Implementing the update() method
+selection
and selectionArgs
arguments used by
+ {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} and
+ {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+ ContentProvider.query()}. This may allow you to re-use code between these methods.
+Implementing the onCreate() method
+
+public class ExampleProvider extends ContentProvider
+
+ /*
+ * Defines a handle to the database helper object. The MainDatabaseHelper class is defined
+ * in a following snippet.
+ */
+ private MainDatabaseHelper mOpenHelper;
+
+ // Defines the database name
+ private static final String DBNAME = "mydb";
+
+ // Holds the database object
+ private SQLiteDatabase db;
+
+ public boolean onCreate() {
+
+ /*
+ * Creates a new helper object. This method always returns quickly.
+ * Notice that the database itself isn't created or opened
+ * until SQLiteOpenHelper.getWritableDatabase is called
+ */
+ mOpenHelper = new SQLiteOpenHelper(
+ getContext(), // the application context
+ DBNAME, // the name of the database)
+ null, // uses the default SQLite cursor
+ 1 // the version number
+ );
+
+ return true;
+ }
+
+ ...
+
+ // Implements the provider's insert method
+ public Cursor insert(Uri uri, ContentValues values) {
+ // Insert code here to determine which table to open, handle error-checking, and so forth
+
+ ...
+
+ /*
+ * Gets a writeable database. This will trigger its creation if it doesn't already exist.
+ *
+ */
+ db = mOpenHelper.getWritableDatabase();
+ }
+}
+
+
+...
+// A string that defines the SQL statement for creating a table
+private static final String SQL_CREATE_MAIN = "CREATE TABLE " +
+ "main " + // Table's name
+ "(" + // The columns in the table
+ " _ID INTEGER PRIMARY KEY, " +
+ " WORD TEXT"
+ " FREQUENCY INTEGER " +
+ " LOCALE TEXT )";
+...
+/**
+ * Helper class that actually creates and manages the provider's underlying data repository.
+ */
+protected static final class MainDatabaseHelper extends SQLiteOpenHelper {
+
+ /*
+ * Instantiates an open helper for the provider's SQLite data repository
+ * Do not do database creation and upgrade here.
+ */
+ MainDatabaseHelper(Context context) {
+ super(context, DBNAME, null, 1);
+ }
+
+ /*
+ * Creates the data repository. This is called when the provider attempts to open the
+ * repository and SQLite reports that it doesn't exist.
+ */
+ public void onCreate(SQLiteDatabase db) {
+
+ // Creates the main table
+ db.execSQL(SQL_CREATE_MAIN);
+ }
+}
+
+
+
+
+Implementing ContentProvider MIME Types
+
+
+MIME types for tables
+
+
+vnd
+
+
+ android.cursor.item/
+ android.cursor.dir/
+ vnd.<name>
.<type>
+ <name>
and <type>
.
+ The <name>
value should be globally unique,
+ and the <type>
value should be unique to the corresponding URI
+ pattern. A good choice for <name>
is your company's name or
+ some part of your application's Android package name. A good choice for the
+ <type>
is a string that identifies the table associated with the
+ URI.
+ com.example.app.provider
, and it exposes a table named
+ table1
, the MIME type for multiple rows in table1
is:
+
+vnd.android.cursor.dir/vnd.com.example.provider.table1
+
+table1
, the MIME type is:
+
+vnd.android.cursor.item/vnd.com.example.provider.table1
+
+MIME types for files
+.jpg
,
+ .png
, and .gif
format.
+ If an application calls {@link android.content.ContentResolver#getStreamTypes(Uri, String)
+ ContentResolver.getStreamTypes()} with the filter string image/*
(something that
+ is an "image"),
+ then the {@link android.content.ContentProvider#getStreamTypes(Uri, String)
+ ContentProvider.getStreamTypes()} method should return the array:
+
+{ "image/jpeg", "image/png", "image/gif"}
+
+.jpg
files, then it can call
+ {@link android.content.ContentResolver#getStreamTypes(Uri, String)
+ ContentResolver.getStreamTypes()} with the filter string *\/jpeg
, and
+ {@link android.content.ContentProvider#getStreamTypes(Uri, String)
+ ContentProvider.getStreamTypes()} should return:
+
+{"image/jpeg"}
+
+null
.
+Implementing a Contract Class
+public final
class that contains constant definitions for the
+ URIs, column names, MIME types, and other meta-data that pertain to the provider. The class
+ establishes a contract between the provider and other applications by ensuring that the provider
+ can be correctly accessed even if there are changes to the actual values of URIs, column names,
+ and so forth.
+.jar
file you provide.
+Implementing Content Provider Permissions
+
+
+Implementing permissions
+
+ <provider>
element. You can set permissions that apply to the entire provider,
+ or to certain tables, or even to certain records, or all three.
+
+ <permission>
elements in your manifest file. To make the
+ permission unique to your provider, use Java-style scoping for the
+
+ android:name
attribute. For example, name the read permission
+ com.example.app.provider.permission.READ_PROVIDER
.
+
+
+
+
+
+
+
+
+ android:permission
attribute of the
+
+ <provider>
element.
+
+ android:readPermission
and
+
+ android:writePermission
attributes of the
+
+ <provider>
element. They take precedence over the permission required by
+
+ android:permission
.
+
+ <path-permission>
child element of the
+
+ <provider>
element. For each content URI you specify, you can specify a
+ read/write permission, a read permission, or a write permission, or all three. The read and
+ write permissions take precedence over the read/write permission. Also, path-level
+ permission takes precedence over provider-level permissions.
+
+ android:grantUriPermissions
attribute of the
+
+ <provider>
element, or add one or more
+
+ <grant-uri-permission>
child elements to your
+
+ <provider>
element. If you use temporary permissions, you have to call
+ {@link android.content.Context#revokeUriPermission(Uri, int)
+ Context.revokeUriPermission()} whenever you remove support for a content URI from your
+ provider, and the content URI is associated with a temporary permission.
+ true
, then the system will grant temporary
+ permission to your entire provider, overriding any other permissions that are required
+ by your provider-level or path-level permissions.
+ false
, then you must add
+
+ <grant-uri-permission>
child elements to your
+
+ <provider>
element. Each child element specifies the content URI or
+ URIs for which temporary access is granted.
+
+ android:grantUriPermissions
attribute is not present, it's assumed to be
+ false
.
+ The <provider> Element
+
+ <provider>
element. The Android system gets the following information from
+ the element:
+
+
+
+
+
+android:name
+
)
+
+
+
+ android:grantUriPermssions
: Temporary permission flag.
+
+ android:permission
: Single provider-wide read/write permission.
+
+ android:readPermission
: Provider-wide read permission.
+
+ android:writePermission
: Provider-wide write permission.
+
+
+
+ android:enabled
: Flag allowing the system to start the provider.
+
+ android:exported
: Flag allowing other applications to use this provider.
+
+ android:initOrder
: The order in which this provider should be started,
+ relative to other providers in the same process.
+
+ android:multiProcess
: Flag allowing the system to start the provider
+ in the same process as the calling client.
+
+ android:process
: The name of the process in which the provider should
+ run.
+
+ android:syncable
: Flag indicating that the provider's data is to be
+ sync'ed with data on a server.
+
+ <provider>
+ element.
+
+
+
+ android:icon
: A drawable resource containing an icon for the provider.
+ The icon appears next to the provider's label in the list of apps in
+ Settings > Apps > All.
+
+ android:label
: An informational label describing the provider or its
+ data, or both. The label appears in the list of apps in
+ Settings > Apps > All.
+
+ <provider>
element.
+ Intents and Data Access
+In this document
-
-
-Key classes
+
+Topics
-
-See also
-
+
+Related Samples
+
+
Content Provider Basics
-
-{@link android.content.Context#getContentResolver
-getContentResolver()}
from within the implementation of an Activity
-or other application component:
-ContentResolver cr = getContentResolver();
-
-The data model
-
-
-
-
-
-
- _ID
- NUMBER
- NUMBER_KEY
- LABEL
- NAME
- TYPE
-
-
- 13
- (425) 555 6677
- 425 555 6677
- Kirkland office
- Bully Pulpit
- {@code TYPE_WORK}
-
-
- 44
- (212) 555-1234
- 212 555 1234
- NY apartment
- Alan Vain
- {@code TYPE_HOME}
-
-
- 45
- (212) 555-6657
- 212 555 6657
- Downtown office
- Alan Vain
- {@code TYPE_MOBILE}
-
-
-53
- 201.555.4433
- 201 555 4433
- Love Nest
- Rex Cars
- {@code TYPE_HOME}
- URIs
-
-
{@code android.provider.Contacts.Photos.CONTENT_URI}
-Querying a Content Provider
-
-
-
-
-Making the query
-
-{@link android.content.ContentResolver#query ContentResolver.query()}
-method or the {@link android.app.Activity#managedQuery
-Activity.managedQuery()}
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
-{@link android.app.Activity#startManagingCursor
-Activity.startManagingCursor()}
.
-{@link android.content.ContentResolver#query query()}
-or {@link android.app.Activity#managedQuery managedQuery()}
is the provider URI
-— the {@code CONTENT_URI} constant that identifies a particular
-ContentProvider and data set (see URIs earlier).
-{@link android.content.ContentUris#withAppendedId
-ContentUris.withAppendedId()}
and {@link
-android.net.Uri#withAppendedPath Uri.withAppendedPath()}
,
-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:
-
-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);
-
-
-{@link android.content.ContentResolver#query query()}
-and {@link android.app.Activity#managedQuery managedQuery()}
methods delimit
-the query in more detail. They are:
-
-
-
-
-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");
-
-
-What a query returns
-
-
-
-
-
-
-
- _ID
- _COUNT
- NAME
- NUMBER
-
-
- 44
- 3
- Alan Vain
- 212 555 1234
-
-
- 13
- 3
- Bully Pulpit
- 425 555 6677
-
-
-
-53
- 3
- Rex Cars
- 201 555 4433
- Reading retrieved data
-
-{@link
-android.database.Cursor#getString getString()}
, {@link
-android.database.Cursor#getInt getInt()}
, and {@link
-android.database.Cursor#getFloat getFloat()}
.
-(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.
-
-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());
-
- }
-}
-
-
-{@link android.database.Cursor#getBlob Cursor.getBlob()}
.
-It returns a byte array.
-{@link android.content.ContentResolver#openInputStream
-ContentResolver.openInputStream()}
to get an
-{@link java.io.InputStream} object that you can use to read the data.
-Modifying Data
-
-
-
-
-Adding records
-
-{@link
-android.content.ContentResolver#insert ContentResolver.insert()}
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:
-
-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);
-
-
-
-Adding new values
-
-
-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);
-
-
-{@link android.content.ContentValues#put
-ContentValues.put()}
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
-{@link android.content.ContentResolver#openOutputStream
-ContentResolver.openOutputStream()}
-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.)
-
-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);
-}
-
-
-
-Batch updating records
-
-{@link
-android.content.ContentResolver#update ContentResolver.update()}
-method with the columns and values to change.
-Deleting a record
-
-{@link
-android.content.ContentResolver#delete ContentResolver.delete()}
-with the URI of a specific row.
-{@link
-android.content.ContentResolver#delete ContentResolver.delete()}
-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. (Caution:
-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!).
-Creating a Content Provider
-
-
-
-
-Extending the ContentProvider class
-
-
{@code insert()}
-
{@code update()}
-
{@code delete()}
-
{@code getType()}
-
{@code onCreate()}{@link android.content.ContentResolver#notifyChange(android.net.Uri,android.database.ContentObserver)
-ContentResolver.notifyChange()}
to notify listeners when there are
-modifications to the data.
-
-
-
-public static final Uri CONTENT_URI =
- Uri.parse("content://com.example.codelab.transportationprovider");
-
-
{@code content://com.example.codelab.transportationprovider/air/domestic}
-
{@code content://com.example.codelab.transportationprovider/air/international}{@link
-android.content.ContentProvider#getType ContentProvider.getType()}
.
-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:
-
-
-{@link
-android.content.ContentResolver#openInputStream ContentResolver.openInputStream()}
-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.Declaring the content provider
-
-
-<provider android:name="com.example.autos.AutoInfoProvider"
- android:authorities="com.example.autos.autoinfoprovider"
- . . . />
-</provider>
-
-
-
{@code content://com.example.autos.autoinfoprovider/gm/compact}
-
{@code content://com.example.autos.autoinfoprovider/gm/suv}Content URI Summary
-
-
-
-
-
+ Content providers manage access to a structured set of data. They encapsulate the
+ data, and provide mechanisms for defining data security. Content providers are the standard
+ interface that connects data in one process with code running in another process.
+<provider android:name=".TransportationProvider"
- android:authorities="com.example.transportationprovider"
- . . . >
+ When you want to access data in a content provider, you use the + {@link android.content.ContentResolver} object in your + application's {@link android.content.Context} to communicate with the provider as a client. + The {@link android.content.ContentResolver} object communicates with the provider object, an + instance of a class that implements {@link android.content.ContentProvider}. The provider + object receives data requests from clients, performs the requested action, and + returns the results. +
++ You don't need to develop your own provider if you don't intend to share your data with + other applications. However, you do need your own provider to provide custom search + suggestions in your own application. You also need your own provider if you want to copy and + paste complex data or files from your application to other applications. +
+
+ Android itself includes content providers that manage data such as audio, video, images, and
+ personal contact information. You can see some of them listed in the reference
+ documentation for the
+ android.provider
+
package. With some restrictions, these providers are accessible to any Android
+ application.
+
+ The following topics describe content providers in more detail: +
+