編輯:關於android開發
本節講述了如何從provider取得數據,使用用戶詞典作為例子.
為了清析易懂,本節中調用ContentResolver.query()的代碼片斷置於"UI 線程"中.但是,在實際代碼中,你應該在另一個線程執行查詢動作,這樣做的一種方法是使用CursorLoader 類.而,那幾行示例代碼僅是片斷,它們不能展示一個完整的應用.
要從provider取得data,須依如下步驟:
1 請求provider的讀權限.
2 定義發送請求到provider的代碼.
要從一個provider中獲取數據,你的應用需要對目標provider具有"讀權限".你不能在運行時請求此權限,而只能在manifest文件中使用 <uses-permission> 元素指定你的權限需求.當你在manifest中指定此元素時,你實際上就是在為你的應用請求這個權限.當用戶安裝你的應用時,就表示同意了這個權限請求.
要找到你使用的provider讀權限的所對應的准確名字,以及其它用於provider的權限的名字,請浏覽provider的文檔.
關於操作provider的權限的角色的更多信息,請見Content Provider權限一節.
用戶詞典Provider在它的manifest 中定義了android.permission.READ_USER_DICTIONARY 權限,所以一個想讀取它內容的應用必須請求此權限.
獲取數據的下一步是構建一個請求(query).這裡的第一個代碼片段定義了一些用於操作用戶詞典Provider的變量:
// "projection" 定義了要返回的各列們
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
};
// 定義一個包含"select"條款的字符串
String mSelectionClause = null;
// 初始化一個包含"select"參數的字符串
String[] mSelectionArgs = {""};
下一個代碼片段演示了如何使用ContentResolver.query(),將用戶詞典Provider作為一個例子.一個provider客戶端查詢極像一個SQL查詢,它包含了要返回的一坨column們,一堆篩選條件,和一個排序方式.
查詢返回的column集合被稱作projection (變量 mProjection).
指定返回的列的語句被分解為選擇條款和選擇參數兩部分.選擇條款是邏輯和布爾表達式,列名以及值的組合體(變量mSelection).如果你在其中指定了使用 ? 來代表一個值,查詢方法就會從選擇參數部分取得這個值(變量mSelectionArgs).
在下一個代碼片段中,如果用戶沒有輸入單詞,選擇條款就被設為null,並且查詢會反回所provider中所有的單詞.如果用戶輸入了單詞,選擇條款就被設置為UserDictionary.Words.Word + " = ?" 並且選擇參數(數組)的第一項被設置為用戶輸入的單詞.
/*
* 定義一個一維的字符串數組來容納選擇參數們
*/
String[] mSelectionArgs = {""};
// 從界面中獲取一個單詞
mSearchString = mSearchWord.getText().toString();
// 記住要在此插插入代碼檢查不合法的或惡意的輸入.
// 如果單詞是空的,則獲取所有數據
if (TextUtils.isEmpty(mSearchString)) {
// 設置選擇條款為null就會返回所有單詞
mSelectionClause = null;
mSelectionArgs[0] = "";
} else {
// 構造一個匹配用戶輸入的單詞的選擇條款
mSelectionClause = " = ?";
// 將用戶輸入的單詞置於選擇參數中
mSelectionArgs[0] = mSearchString;
}
// 執行查詢並返回游標對象
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
// 有些provider在出錯時返回null,有拋出異常
if (null == mCursor) {
/*
* 在此插入代碼處理錯誤.記住不要使用游標! 你可能要調用
* android.util.Log.e()把錯誤記錄的日志
*
*/
// 如果游標是空的,找不到匹配的provider
} else if (mCursor.getCount() < 1) {
/*
* 在此插入代碼來通知用戶,查找不成功.這也不能完全算是個錯誤.你可能想為用戶提供插入一個新行或重新輸入查詢單詞的選項
*/
} else {
// 在此插入代碼,利用返回的結果做想做的事
}
查詢與下面的SQL語句等價:
SELECT _ID, word, frequency, locale FROM words WHERE word = <userinput> ORDER BY word ASC;
在此SQL 語句中,以實際的列名代替了內置的類別常量.
如果被content provider管理的數據是一個SQL 數據庫,在原始的SQL語句中包含不可信的數據會導致SQL注入.
思考以下選擇條款:
// 通過連接用戶輸入到列名來構造一個選擇條款
String mSelectionClause = "var = " + mUserInput;
如果你這樣做,你就允許用戶連接惡意的SQL語句到你的SQL語句中.例如,用戶可以輸入"nothing; DROP TABLE *;" ,這將在選擇條款中變為 var = nothing; DROP TABLE *;..既然選擇條款被作為SQL語句,這就可能導致provider刪除SQLite數據庫中的所有的表(除非provider被設置成捕獲SQL injection 陰謀).
要避免此問題,應使用一個運用?作為可替換參數的選擇條款和一個作為選擇參數的數組.當你這樣做時,用戶輸入被直接綁定到查詢而不是被解釋為SQL語句的一部分.因為它不被認為是SQL,於是用戶輸入就不能注入惡意SQL.使用以下選擇條款來代替連接用戶輸入的那個:
// 構造一個帶有占位符的選擇條款
String mSelectionClause = "var = ?";
像這樣建立起選擇參數數組:
// 定義一個數組來容納選擇參數
String[] selectionArgs = {""};
像這樣把一個值置入選擇參數數組中:
// Sets the selection argument to the user's input
selectionArgs[0] = mUserInput;
一個使用?作為占位符的選擇條款+一個選擇參數數組是指定一個選擇器的最佳方式,即使provider不是基於SQL數據庫的.
客戶端方法ContentResolver.query() 總是返回一個包含所查詢的列們的Cursor .一個Cursor 對象提供了隨機的讀取它所包含的行和列的能力.使用Cursor 的方法們,你可以迭代結果中的行,決定每列的數據類型,從列獲得數據,以及檢測結果的其它屬性.一些Cursor 的實現會在provider的數據改變時自動更新,或在Cursor 改變時觸發監聽者的方法,或者兩者都支持.
注: 一個provider可能跟據構建查詢的對象的性質限制對某些列的操作.例如,聯系人Provider會禁止同步適配器操作某些列,所以它不會把它們返回給一個activity或service.
如果沒有符合選擇條件的行,provider返回一個Cursor 對象,其Cursor.getCount() 為0 (一個空cursor).
如果一個內部錯誤發生,查詢結果會因provider的不同而不同.它可能返回null,也可能拋出一個Exception.
既然一個Cursor 是行組成的"列表",那麼一個和顯示Cursor 內容的好方法就是把它鏈接到一個ListView 上,通過SimpleCursorAdapter.
下面的代碼片段是銜接前面的代碼來的.它創建一個SimpleCursorAdapter 對象,包含有查詢返回的Cursor ,然後設置這個對象為ListView的適配器.
// 定義要從Cursor取出的並要加載到view中的列們
String[] mWordListColumns =
{
UserDictionary.Words.WORD, // Contract class constant containing the word column name
UserDictionary.Words.LOCALE // Contract class constant containing the locale column name
};
// 定義一個View ID組成的列表,它們將接收每行的Cursor列的值
int[] mWordListItems = { R.id.dictWord, R.id.locale};
// Creates a new SimpleCursorAdapter
mCursorAdapter = new SimpleCursorAdapter(
getApplicationContext(), // The application's Context object
R.layout.wordlistrow, // ListView的一行的layout
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)
// 將適配器設置給ListView
mWordList.setAdapter(mCursorAdapter);
注:要使Cursor支持ListView,cursor必須包含一個叫做_ID的列,因此,上面所示的查詢從"單詞"表中取出了_ID ,當然ListView 可以不顯示它.這條限制同時也解釋了為毛大多數provider在它們的表中都具有一個_ID 列.
你可以使用查詢結果做更多是事情,而不是僅簡單地顯示它們.比如,你可以從用戶詞典中獲取拼法然後在其它provider中查找它們.要這樣做,你需在Cursor中迭代所有的行.
// 獲取叫做"word"的列的序號
int index = mCursor.getColumnIndex(UserDictionary.Words.WORD);
/*
* 僅在cursor有效時執行下面語句.如果發生內部錯誤,用戶詞典Provider返回null.
* 其它provider可能拋出一個異常而不是返回null.
*/
if (mCursor != null) {
/*
* 移到cursor中的下一行.在第一次移動之前,
* "行指針" 為-1,並且,如果你想獲取那個位置的數據,你將得到一個異常
*/
while (mCursor.moveToNext()) {
// 從列中獲取值.
newWord = mCursor.getString(index);
// 在此插入代碼處理獲取到的單詞
...
// 循環結束
}
} else {
// 如果cursor為null或前面拋出了異常,在處插入代碼報告錯誤.
}
Cursor 的實現包含了多個"get" 方法,用於從對象中獲取不同類型的數據.例如,前面的代碼片段使用getString().它們也具有一個getType() 方法,用它可以返回的值代表了數據的類型.
Android NDK開發初識,androidndk初識 神秘的Android NDK開發往往眾多程序員感到興奮,但又不知它為何物,由於近期開發應用時,為了是開發的.a
使用Eclipse開發,Java Compiler中Annotation Processin不出現的解決方案,eclipseannotation第一步:在Eclipse菜
硅谷社交8--聯系人列表頁面,硅谷社交8--聯系人 1.是否有邀請信息紅點的設置 // 獲取當前是否有新的邀請信息 boolean is_notify = SpUtil
Android之genymotion模擬器安裝於配置,androidgenymotion 今天是雙休日,可憐沒人陪,只好一個人玩電腦了,之前別人一直給我推薦genymo