android contentprovider api,Content Provider Basics
一個(gè)內(nèi)容提供者訪問(wèn)數(shù)據(jù)的中央資源庫(kù)。提供者是應(yīng)用程序的一部分,提供自己的操作數(shù)據(jù)的UI。然而,內(nèi)容提供者主要是被其他應(yīng)用程序引用,通過(guò)提供者客戶對(duì)象訪問(wèn)提供者。提供者和提供者客戶端為數(shù)據(jù)提供一個(gè)一致的,標(biāo)準(zhǔn)的接口,也處理進(jìn)程間的聯(lián)系和數(shù)據(jù)安全訪問(wèn)。
本文討論下面幾個(gè)方面的基礎(chǔ):
:
內(nèi)容提供類如何工作。
從內(nèi)容提供者獲取數(shù)據(jù)的API。
向內(nèi)容提供者你插入、更新、刪除數(shù)據(jù)的API。
便利的使用內(nèi)容提供者的API。
Overview
提供者向應(yīng)用程序呈現(xiàn)數(shù)據(jù)就像一個(gè)或多張表,就像是在關(guān)系數(shù)據(jù)庫(kù)里一樣。一行顯示一些數(shù)據(jù)類型的實(shí)例,列的每行顯示實(shí)例數(shù)據(jù)集合的獨(dú)立數(shù)據(jù)。
例如:一個(gè)在android平臺(tái)里內(nèi)建的提供者是用戶詞典,用來(lái)存儲(chǔ)用戶想保存的非標(biāo)準(zhǔn)的拼寫(xiě)。表一說(shuō)明了在提供者的表里數(shù)據(jù)是如何的:
Table 1: Sample user dictionary table.
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
在表1里,每行的單詞都是在標(biāo)準(zhǔn)詞典里找不到的。沒(méi)列有一些和單詞相關(guān)的數(shù)據(jù),比如:它所屬的區(qū)域。列頭是列的名字。引用列的區(qū)域,你可以引用它的locale列。對(duì)于提供者來(lái)講,自動(dòng)認(rèn)為列的_ID是“主鍵”。
注意:提供者并不是一定需要主鍵,它不需要使用_ID 作為主鍵的列名如果已經(jīng)存在。然而,如果你想綁定一個(gè)提供者到一個(gè)ListView,一個(gè)列名是需要_ID的。對(duì)于這個(gè)需要的解釋,在這里:Displaying query results。
訪問(wèn)一個(gè)提供者
一個(gè)應(yīng)用程序通過(guò)客戶類ContentResolver訪問(wèn)內(nèi)容提供者的數(shù)據(jù)。這個(gè)函數(shù)有一個(gè)在提供者對(duì)象里同名的函數(shù),是一個(gè)ContentProvider子類的實(shí)例。函數(shù)ContentResolver提供”CRUD”的基礎(chǔ)(創(chuàng)建,獲取,更新,刪除)函數(shù)。
擁有提供者的應(yīng)用程序進(jìn)程的ContentResolver對(duì)象和ContentProvider對(duì)象可以自動(dòng)處理進(jìn)程間的數(shù)據(jù)交換。
注意:訪問(wèn)一個(gè)提供者,應(yīng)用程序通常在manifest文件里請(qǐng)求指定的權(quán)限。在Content Provider Permissions一節(jié)里有更多細(xì)節(jié)。
例如,從User Dictionary Provider獲取單詞的一列和語(yǔ)言環(huán)境,你調(diào)用ContentResolver.query().query()函數(shù)調(diào)用定義的函數(shù)[ ContentProvider.query()]。下面的代碼顯示的是一個(gè)[ ContentResolver.query()]調(diào)用:
// 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
Table 2 shows how the arguments to
Table 2: Query() compared to SQL query.
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
Content URIs
一個(gè)內(nèi)容URI是一個(gè)定于數(shù)據(jù)的URI。內(nèi)容URI包含一個(gè)提供者的符號(hào)名(它的權(quán)限)和一個(gè)指向一個(gè)表(一個(gè)路徑)的名字。當(dāng)你調(diào)用客戶端函數(shù)來(lái)訪問(wèn)表的時(shí)候,這個(gè)URI是參數(shù)的一個(gè)。
上面的代碼,常量CONTENT_URI包含user dictionary的單詞表的內(nèi)容URI。對(duì)象ContentResolver 解析URI的權(quán)限,使用它。ContentResolver能分派查詢參數(shù)來(lái)更正提供者。
使用內(nèi)容URI的部分路徑來(lái)選擇想訪問(wèn)的表。提供者的每個(gè)外在的表都有一個(gè)路徑。
之前的代碼,“words”表完整的URI是:
content://user_dictionary/words
字符串user_dictionary是提供者的權(quán)限,字符串words是表的路徑。字符串content://(配置)通常指示標(biāo)識(shí)這項(xiàng)是一個(gè)內(nèi)容URI。
提供者允許你通過(guò)附加在URI后的一個(gè)ID值來(lái)訪問(wèn)表的一行。例如,從獲取_ID是4的一行,你可以使用內(nèi)容URI:
Uri singleUri = ContentUri.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
通常獲取一個(gè)行集合的時(shí)候使用id并且想要更新或者刪除它們中的一個(gè)。
注意:類Uri和Uri.Builder包含便利的函數(shù)來(lái)從一個(gè)字符串格式化Uri對(duì)象。ContetnUris包含一個(gè)便利的函數(shù)withAppendedId()來(lái)向URI最近一個(gè)id。之前的片段是用來(lái)追加id到Userdictionary。
從提供者里獲取數(shù)據(jù)
從提供者里獲取數(shù)據(jù),例子使用User Dictionary Provider。
為了清晰,這一節(jié)的代碼段在“UI線程”里調(diào)用ContentResolver.query()。實(shí)際的代碼,然而,你需要在分開(kāi)的線程里做異步查詢。可以使用CursorLoader實(shí)現(xiàn),更多的信息在Loaders 指南。代碼很短;他們沒(méi)有顯示一個(gè)完整的應(yīng)用。
獲取數(shù)據(jù),有以下的兩個(gè)步驟:
1、需要提供者允許讀訪問(wèn)。
2、發(fā)送一個(gè)query到提供者的代碼。
請(qǐng)求讀訪問(wèn)權(quán)限
從提供者獲取數(shù)據(jù),應(yīng)用程序需要“讀許可”。不可以在運(yùn)行的時(shí)候申請(qǐng);在你的manifest文件里聲明,使用元素?cái)U(kuò)展權(quán)限名,它是提供者定義的。
當(dāng)你在manifest里聲明元素,實(shí)際上你就是申請(qǐng)權(quán)限。當(dāng)用戶安裝引用程序,也就隱式的授予了請(qǐng)求。
為你使用的提供者查找確切的讀訪問(wèn)權(quán)限的名字,就像其它提供者的訪問(wèn)權(quán)限的名字一樣,參考提供者文檔。
在Content Provider Permissions一節(jié),有關(guān)于訪問(wèn)提供者的權(quán)限的更多信息。
User Dictionary Provider在manifest文件里定義android.permission.READ_USER_DICTIONARY權(quán)限,應(yīng)用程序想從提供者讀取需要這個(gè)權(quán)限。
構(gòu)造查詢
下一步獲取數(shù)據(jù)時(shí)提供者構(gòu)造一個(gè)查詢。第一個(gè)片段為訪問(wèn)User Dictionary Provider定義了一些變量:
// 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 = {""};
下面的代碼顯示如何使用ContentResolver.query(),例子使用。提供者客戶端查詢是類似SQL查詢,它返回一個(gè)列的集合,選擇標(biāo)準(zhǔn)集,排序命令。
查詢需要返回的列的集合被疑個(gè)Projection(變量mProjection)調(diào)用。知道獲取行的表達(dá)式是分到一個(gè)選擇語(yǔ)句和一個(gè)選擇參數(shù)里的。選擇語(yǔ)句是一個(gè)邏輯、布爾值、列名、值(變量mSelection)復(fù)合表達(dá)式。如果你指定替換參數(shù)?來(lái)代替一個(gè)值,查詢函數(shù)從選擇參數(shù)數(shù)列里獲取值(變量mSelectionArgs)。
下面的片段,如果用戶不輸入一個(gè)單詞,設(shè)置為null,查詢返回提供者里所有的單詞。如果用戶輸入一個(gè)單詞,設(shè)置 UserDictionary.Words.Word + " = ?" 并且選擇參數(shù)數(shù)組的第一個(gè)元素設(shè)置為用戶輸入的。
/*
* 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 = UserDictionary.Words.WORD + " = ?";
// 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
}
這個(gè)查詢和SQL語(yǔ)句類似。
SELECT _ID, word, frequency, locale FROM words WHERE word = ORDER BY word ASC;
這個(gè)SQL語(yǔ)句,實(shí)際的列名用于替代合約類的常量。
防止惡意插入
如果通過(guò)提供者管理的數(shù)據(jù)在SQL數(shù)據(jù)庫(kù)里,包括外部不可信的數(shù)據(jù)進(jìn)入原始的SQL語(yǔ)句會(huì)導(dǎo)致SQL注入。 考慮這種情況:
Consider this selection clause:
// Constructs a selection clause by concatenating the user's input to the column name
String mSelectionClause = "var = " + mUserInput;
如果你這樣做,你就允許用戶串聯(lián)惡意的SQL到你的SQL語(yǔ)句里。例如:用戶可以為mUserInput輸入“nothing; DROP TABLE *;”結(jié)果選擇語(yǔ)句var = nothing; DROP TABLE *;
當(dāng)選擇語(yǔ)句被認(rèn)為是一個(gè)SQL語(yǔ)句,就會(huì)引起提供者擦除SQLite數(shù)據(jù)庫(kù)里所有的表(除非提供者設(shè)置捕獲SQL injection 的語(yǔ)句)。
為了解決這個(gè)問(wèn)題,使用一個(gè)有?作為可替換參數(shù)的選擇語(yǔ)句和一個(gè)分開(kāi)的選擇參數(shù)數(shù)組。這樣做,用戶輸入一個(gè)**到查詢而不是作為SQL語(yǔ)句的一部分被中斷。因?yàn)?#xff0c;它沒(méi)有被視為是SQL,用戶輸入不可以注入惡意的SQL。使用如下的選擇語(yǔ)句,而不是使用級(jí)聯(lián)用戶輸入的語(yǔ)句。
// Constructs a selection clause with a replaceable parameter
String mSelectionClause = "var = ?";
設(shè)置選擇參數(shù)數(shù)組如下:
// Defines an array to contain the selection arguments
String[] selectionArgs = {""};
設(shè)置一個(gè)選擇參數(shù)數(shù)組就如下:
// Sets the selection argument to the user's input
selectionArgs[0] = mUserInput;
?是可替換參數(shù),選擇查詢數(shù)組首選的方法是指定一節(jié),甚至提供者不基于一個(gè)SQL數(shù)據(jù)庫(kù)。
顯示查詢結(jié)果
ContentResolver.query() 函數(shù)總是返回一個(gè)Cursor ,它包含查詢的Projection指定的列,行是匹配查詢選擇標(biāo)準(zhǔn)的。一個(gè)Cursor 對(duì)象提供隨機(jī)的讀行權(quán)限還有它包含的列。使用Cursor 函數(shù),你可以在結(jié)果里遍歷行,決定每列的數(shù)據(jù)類型,獲取列外的數(shù)據(jù),使用結(jié)果的其它屬性。一些Cursor 實(shí)現(xiàn)當(dāng)提供者數(shù)據(jù)變化時(shí)自動(dòng)的更新。或當(dāng)Cursor 改變是觸發(fā)觀察對(duì)象的方法,或者兩者都有。
注意:一個(gè)提供者可能限制訪問(wèn)列基于對(duì)象的屬性來(lái)生成查詢。例如:合約提供者訪問(wèn)一些列來(lái)同步適配器,因此它不返回到Activity或一個(gè)服務(wù)。
如果沒(méi)有匹配選擇標(biāo)準(zhǔn)的行,提供者返回一個(gè)Cursor對(duì)象,它的Cursor.getCount() 是0(一個(gè)空的cursor)。
如果內(nèi)部發(fā)生一個(gè)錯(cuò)誤,查詢結(jié)果依靠指定的提供者。可能選擇返回null,或者拋出異常。
如果Cursor是行的列表,顯示Cursor內(nèi)容的方法是把它通過(guò)SimpleCursorAdapter和一個(gè)ListView連接。
下面的代碼是前面代碼的繼續(xù)。它創(chuàng)建一個(gè)對(duì)象SimpleCursorAdapter包含通過(guò)查詢獲取的Cursor,設(shè)置這個(gè)對(duì)象作為L(zhǎng)istView的適配器。
// 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);
注意:備份一個(gè)ListView和一個(gè)Cursor,curso需要包含一個(gè)列名叫_ID。因?yàn)?#xff0c;查詢顯示之前返回的單詞表的_ID列,甚至ListView不顯示。這也解釋了為什么每個(gè)表的列有一個(gè)_ID。
從查詢結(jié)果里獲取數(shù)據(jù)
不是簡(jiǎn)單顯示你查詢的結(jié)果,你可使用它們做別的任務(wù)。例如:你可以從user dictionary獲取拼寫(xiě)并且在其它提供者里查詢。可以在Cursor里遍歷行:
// 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.
}
Cursor實(shí)現(xiàn)一系列的“get”函數(shù),為從對(duì)象獲取不同類型的數(shù)據(jù)。例如:前面的代碼使用函數(shù)getString()。getType()函數(shù)返回一個(gè)表示數(shù)據(jù)類型的值。
內(nèi)容提供者權(quán)限
一個(gè)內(nèi)容提供者可以指明其它需要訪問(wèn)數(shù)據(jù)的程序的權(quán)限。權(quán)限確保用戶知道程序想要訪問(wèn)的數(shù)據(jù)。基于提供者的請(qǐng)求,程序請(qǐng)求權(quán)限以此訪問(wèn)提供者。當(dāng)安裝應(yīng)用程序的時(shí)候,終端用戶看到請(qǐng)求權(quán)限。 如果提供者的程序不指明權(quán)限,其它應(yīng)用程序不可以訪問(wèn)數(shù)據(jù)。然而,提供者程序的組件擁有所有的讀寫(xiě)權(quán),不管有沒(méi)有指定。
之前提到的,User Dictionary Provider請(qǐng)求android.permission.READ_USER_DICTIONARY 權(quán)限來(lái)獲取數(shù)據(jù)。提供者為插入、更新、刪除數(shù)據(jù)分開(kāi)android.permission.WRITE_USER_DICTIONARY 權(quán)限。
獲取訪問(wèn)提供者訪問(wèn)的權(quán)限,一個(gè)應(yīng)用程序需要在manifest文件里有元素。當(dāng)Android包管理器安裝應(yīng)用程序,用戶必須同意程序請(qǐng)求的所有權(quán)限。如果用戶允許,包管理器繼續(xù)安裝;如果用戶不允許,包管理器終止安裝。 下面的元素請(qǐng)求User Dictionary Provider讀訪問(wèn)。
關(guān)于提供者權(quán)限的影響,更多的信息在Security and Permissions 。
插入,更新,刪除數(shù)據(jù)
一些你從提供者獲取數(shù)據(jù)的方法,你使用提供者客戶端和提供者的ContentProvider 來(lái)修改數(shù)據(jù)。你調(diào)用函數(shù)**。提供者和提供者客戶端自動(dòng)處理安全和進(jìn)程間通信。
插入數(shù)據(jù)
向一個(gè)提供者插入數(shù)據(jù),你可以調(diào)用。這個(gè)函數(shù)插入一個(gè)新的行,返回該行的內(nèi)容URI。以下代碼顯示如何向一個(gè)User Dictionary Provider插入新行:
這里有代碼
代碼段不需要添加-ID列,因?yàn)榱械木S護(hù)是自動(dòng)的。如果提供者給每個(gè)添加的行分配一個(gè)獨(dú)一無(wú)二的-ID值。提供者使用這個(gè)值作為表的主鍵。
newUri 返回的內(nèi)容URI指明新增加的行,使用如下格式:
content://user_dictionary/words/
The 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.
To get the value of _ID from the returned
Updating data
To update a row, you use a null.
The following snippet changes all the rows whose locale has the language "en" to a
have a locale of 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
);
You should also sanitize user input when you call
Protecting against malicious input.
Deleting data
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.
// 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
);
You should also sanitize user input when you call
Protecting against malicious input.
Provider Data Types
Content providers can offer many different data types. The User Dictionary Provider offers only
text, but providers can also offer the following formats:
integer
long integer (long)
floating point
long floating point (double)
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
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 Contract Classes).
You can also determine the data type by calling
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
The section MIME Type Reference describes the
syntax of both standard and custom MIME types.
Alternative Forms of Provider Access
Three alternative forms of provider access are important in application development:
Batch access: You can create a batch of access calls with methods in
the
Asynchronous queries: You should do queries in a separate thread. One way to do this is to
use a Loaders guide demonstrate
how to do this.
Data access via intents: Although you can't send an intent
directly to a provider, you can send an intent to the provider's application, which is
usually the best-equipped to modify the provider's data.
Batch access and modification via intents are described in the following sections.
Batch access
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 authority to this
method, rather than a particular content URI, which allows each
The description of the Contact Manager
sample application contains an example of batch access in its ContactAdder.java
source file.
Displaying data using a helper app
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
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
Data access via intents
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.
Getting access with temporary permissions
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
Security and Permissions guide,
in the section "URI Permissions".
For example, you can retrieve data for a contact in the Contacts Provider, even if you don't
have the
Your application sends an intent containing the action
Because this intent matches the intent filter for the
People app's "selection" activity, the activity will come to the foreground.
In the selection activity, the user selects a
contact to update. When this happens, the selection activity calls
Your activity returns to the foreground, and the system calls your activity's
With the content URI from the result intent, you can read the contact's data
from the Contacts Provider, even though you didn't request permanent read access permission
to the provider in your manifest. You can then get the contact's birthday information
or his or her email address and then send the e-greeting.
Using another application
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
Contract Classes
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
For example, the User Dictionary Provider has a contract class
String[] mProjection =
{
UserDictionary.Words._ID,
UserDictionary.Words.WORD,
UserDictionary.Words.LOCALE
};
Another contract class is
MIME Type Reference
Content providers can return standard MIME media types, or custom MIME type strings, or both.
MIME types have the format
type/subtype
For example, the well-known MIME type 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.
Custom MIME type strings, also called "vendor-specific" MIME types, have more
complex type and subtype values. The type value is always
vnd.android.cursor.dir
for multiple rows, or
vnd.android.cursor.item
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:
vnd.android.cursor.item/phone_v2
Notice that the subtype value is simply phone_v2.
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 com.example.trains, and it contains the tables
Line1, Line2, and Line3. In response to the content URI
content://com.example.trains/Line1
for table Line1, the provider returns the MIME type
vnd.android.cursor.dir/vnd.example.line1
In response to the content URI
content://com.example.trains/Line2/5
for row 5 in table Line2, the provider returns the MIME type
vnd.android.cursor.item/vnd.example.line2
Most content providers define contract class constants for the MIME types they use. The
Contacts Provider contract class
Content URIs for single rows are described in the section
Content URIs.
總結(jié)
以上是生活随笔為你收集整理的android contentprovider api,Content Provider Basics的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 我国5月增持109亿美元美债,持有量创三
- 下一篇: 支付宝办信用卡成功率高吗