Android内容提供程序
內容提供程序管理對結構化數據集的訪問,它們封裝數據,并供用于定義數據安全性的機制。內容提供程序是連接一個進程中的數據與另一個進程中運行的代碼的標準界面。
將應用的Context中的ContentResolver對象用作客戶端來提供程序通信,可以訪問內容提供程序中的數據。ContentResolver對象會實現ContentProvider的類實例通信,提供程序對象從客戶端接收數據請求,執行請求的操作并返回結果。
內容提供程序以一個或多個表的形式將數據呈現給外部應用,行表示提供程序收集的某種數據類型的實例,行中的每個列表示為實例收集的。
訪問提供程序
應用從具有ContentResolver客戶端對象的內容提供程序訪問數據,此對象具有調用提供程序對象中同名方法的方法,ContentResolver方法可提供程序存儲的基本CRUD(創建,檢索,更新,刪除)功能。客戶端應用進程中ContentResolver對象和擁有提供程序的應用中的ContentProvider對象可自動處理跨進程通信,ContentProvider還可充當其數據存儲區和表格外部顯示之間的抽象層。
內容URI
是用于在提供程序中表示數據的URI,包括整個提供程序的符號名稱,和一個指向表的名稱(路徑)。ContentResolver對象會分析出URI的授權,并通過將該授權與已知提供程序的系統進行比較來解析提供程序,然后,ContentResolver可以將查血的參數分派給正確的提供程序。
ContentProvider使用內容URI的路徑部分來選擇要訪問的表,提供程序通常會為其公開每個表顯示一條路徑。
例如:content://user_dictionary/words
其中user_dictionary字符串是提供程序的授權,words字符串是表的路徑,字符串content://(架構)始終顯示,并將此標識為內容URI
許多提供程序都允許通過將ID值追加到URI末尾來訪問表中的單個行。在檢索到一組行后想要更新或刪除其中某一行時通常用到ID值。
Uri和Uri.Builder 類包含根據字符串構建格式規范的URI對象的便利方法,ContentUris包含一些可以將ID值追加到URI后的方法。例如:
Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI, 4);
提供程序檢索數據
為了說明,本例在UI線程上調用ContentResolver.query(),但在實際代碼中應該在單獨線程上異步執行查詢,使用CursorLoader類,按照以下兩個基本操作執行
1.請求對提供程序的讀取訪問權限
2.定義將查詢發送至提供程序的代碼
在清單文件<uses-permission>中添加讀取訪問權限
構建查詢
// A "projection" defines the columns that will be returned for each row String[] mProjection = {UserDictionary.Words._ID, // Contract class constant for the _ID column nameUserDictionary.Words.WORD, // Contract class constant for the word column nameUserDictionary.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)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 wordsmSelectionClause = 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 tablemProjection, // The columns to return for each rowmSelectionClause // Either null, or the word the user enteredmSelectionArgs, // Either empty, or the string the user enteredmSortOrder); // 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}如果用戶未輸入字詞,則選擇子句將設置為? null ,而且查詢會返回提供程序中的所有字詞。 如果用戶輸入了字詞,選擇子句將設置為? UserDictionary.Words.WORD + " = ?"?且選擇參數數組的第一個元素將設置為用戶輸入的字詞。
防止惡意輸入
如果內容提供程序管理的數據位于 SQL 數據庫中,將不受信任的外部數據包括在原始 SQL 語句中可能會導致 SQL 注入。
要避免此問題,可使用一個用于將? ??作為可替換參數的選擇子句以及一個單獨的選擇參數數組。 執行此操作時,用戶輸入直接受查詢約束,而不解釋為 SQL 語句的一部分。 由于用戶輸入未作為 SQL 處理,因此無法注入惡意 SQL。
String mSelectionClause = "var = ?"; String[] selectionArgs = {""}; selectionArgs[0] = mUserInput;
一個用于將???用作可替換參數的選擇子句和一個選擇參數數組是指定選擇的首選方式,即使提供程序并未基于 SQL 數據庫。
顯示查詢結果 ContentResolver.query()客戶端方法始終會返回符合以下條件的Cursor 包含查詢的投影為匹配查詢選擇條件的行指定的列.Cursor 對象為其包含的行和列提供隨機讀取訪問權限。 通過使用Cursor 方法,您可以循環訪問結果中的行、確定每個列的數據類型、從列中獲取數據,并檢查結果的其他屬性。 某些Cursor 實現會在提供程序的數據發生更改時自動更新對象和/或在Cursor 更改時觸發觀察程序對象中的方法。如果沒有與選擇條件匹配的行,則提供程序會返回Cursor.geeCount()?為 0(空游標)的Cursor?對象。
如果出現內部錯誤,查詢結果將取決于具體的提供程序。它可能會選擇返回?null,或引發Exception
由于Cursor是行“列表”,因此顯示Cursor?內容的良好方式是通過SimpleCursorAdapter將其與ListView?關聯。
內容提供程序權限提供程序的應用可以指定其他應用訪問提供程序的數據所必需的權限。 這些權限可確保用戶了解應用將嘗試訪問的數據。 根據提供程序的要求,其他應用會請求它們訪問提供程序所需的權限。 最終用戶會在安裝應用時看到所請求的權限。
如果提供程序的應用未指定任何權限,則其他應用將無權訪問提供程序的數據。 但是,無論指定權限為何,提供程序的應用中的組件始終具有完整的讀取和寫入訪問權限。
要獲取訪問提供程序所需的權限,應用將通過其清單文件中的<uses-permission> 元素來請求這些權限。Android 軟件包管理器安裝應用時,用戶必須批準該應用請求的所有權限。 如果用戶批準所有權限,軟件包管理器將繼續安裝;如果用戶未批準這些權限,軟件包管理器將中止安裝。插入、更新、刪除數據
與從提供程序檢索數據的方式相同,也可以通過提供程序客戶端和提供程序ContentProvider之間的交互來修改數據。 您通過傳遞到ContentProvider的對應方法的參數來調用 ContentResolver方法。 提供程序和提供程序客戶端會自動處理安全性和跨進程通信。
插入: // 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 URImNewValues // the values to insert );更新: // 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 URImUpdateValues // the columns to updatemSelectionClause // the column to select onmSelectionArgs // the value to compare to );刪除: // 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 URImSelectionClause // the column to select onmSelectionArgs // the value to compare to );提供程序訪問的替代形式 批量訪問:可以通過ContentProviderOperation類中的方法創建一批訪問調用,然后通過ContentResolver.applyBatch()應用它們。 異步查詢:應該在單獨線程中執行查詢,使用CursorLoader對象。 通過Intent訪問數據:盡管無法直接向提供程序發送Intent,但可以向提供程序的應用發送Intent,后者通常具有修改提供程序數據的最佳配置。 協定類 協定類定義幫助應用使用內容 URI、列名稱、 Intent 操作以及內容提供程序的其他功能的常量。 協定類未自動包含在提供程序中;提供程序的開發者需要定義它們,然后使其可用于其他開發者。 Android 平臺中包含的許多提供程序都在軟件包android.provider中具有對應的協定類。總結
以上是生活随笔為你收集整理的Android内容提供程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Service中的绑定服务总结
- 下一篇: Android应用小工具(窗口小部件)