Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> 詳解android Content Provider[6]

詳解android Content Provider[6]

編輯:Android開發實例

創建一個Content Provider
 

content provider管理對中央數據倉庫的存取。你實現一個provider,就是在一個Android應用中實現一個或多個類,再加上manifest文件中的一些元素。你實現一個 ContentProvider的子類,它作為你的provider和其它應也之間的接口。盡管content providers的目的是向其它應用提供數據,但當然也可以在你自己的應用中創建activity來允許用戶來查詢和修改你的provider所管理的數據。

創建之前的准備工作
 

在創建一個provider之前,需做以下工作:
1. 確定你是否需要一個content provider。你如果需要提供一個或多個下列特性,你就需創建一個content provider:
你想向其它應用提供復雜數據或文件。
你想讓用護從你的應用復制復雜的數據到其它應用。
你想使用搜索框架提供自定義的搜索建議。
如果完全是在你的應用內部使用,你的provider不需使用 SQLite數據庫。
2. 如果你還未作出決定,請閱讀主題 Content Provider Basics 來進一步了解provider。
下一步,按以下步驟來創建你的provider:
1. 為你的數據設計原始存儲方式。一個content provider以兩種方式提供數據:
文件數據
指那存儲在文件中的數據,比如圖片,視頻,音頻等。把文件們存儲在你的應用的私有空間。為響應從其它應用發來的對某個文件的請求,你的provider可以為文件提供一個句柄。
"結構化" 數據
指那些存儲於數據庫中的數據、數組或小型結構。數據以兼容於表的形式存儲。一行代表一條數據,就像一個人員或條目清單中的一條。一列代表一條數據中的一部分數據,比如人的名字或條目的價格。存儲這些類型的數據的一個常用方法是使用SQLite數據庫,但是你也可以使用其它形式。要了解android 系統中更多的存儲方式,見 設計數據存儲一節。
2. 具體定義ContentProvider 類和它的方法。此類是你的數據與Android系統中其它東西的接口。要進一步了解此類,見實現ContentProvider類 一節。
3. 定義provider的authority字符串,content URIs,和列的名字。如果你想讓provider的應用處理intent,還要定義intent 的action、附加數據和標志。還要定義對那些要訪問你的數據的應用所需具有的權限。你應該考慮把這些值作為契約定義到另外一個單獨的契約類中。以後就可以向其它的開發者展示這個類。更多關於content URI的信息,見 設計Content URI.一節。更多關於intent的信息,見Intent和數據操作一節。
4. 添加其它可選內容,比如樣本數據或實現 AbstractThreadedSyncAdapter 以實現provider和基於雲的數據之間的數據同步。
 

定義數據存儲
 

一個content provider是一個結構化存儲的數據接口。在你創建這個接口之前,你必須確定如如何存儲數據。你可以以任何你喜歡的方式存儲數據,然後設計讀寫數據的接口。
下面是一些在android中可用的數據存儲技術:
1 Android系統中包含一個 SQLite數據庫API,Android自己的provider使用它來存儲表格類的數據。SQLiteOpenHelper類幫助你創建數據庫,而類SQLiteDatabase是操作數據庫的基礎類。
記住你不是必須使用一個數據庫來實現你的數據倉庫。一個 provider在外部的表現就像一個表的集合,類似於一個關系型數據庫,但是provider的內部實現是可以與此不同的。
2 對於數據存儲,Android具有各種各樣的面向文件的API。要更多的了解文件存儲,請閱讀主題數據存儲。如果你 設計的provider要提供媒體相關的數據,比如音頻和視頻,你可以在provider中將表數據和文件混合來使用。
3 要處理網絡數據,應使用java.net 和 android.net中的類。你也可以同步網絡數據到本地數據存儲中(比如數據庫中),然後以表或文件的形式提供此數據。例子Sample Sync Adapter 演示了這種同步技術。


 

思考數據設計
 

下面是一些設計你的provider的數據結構的技巧:
1 表數據應總是具有一個"主鍵"列,它被用於管理一個代表每各行的唯一數值。你可以使用這個值鏈接某行到其它表中的相關行 (也就是"外鍵")。盡管你可以為此列取任何名字,但使用BaseColumns._ID 才是最佳選擇,因為當把一個provider的查詢結果關聯到一個 ListView 時,需要有一個列叫做 _ID。
2 如果你想提供位圖圖像或其它的非常大的面向文件的數據,那麼應把它存於文件中,然後間接的提供它,而不是直接把數據存儲於一個表中。如果你這樣做了,你還需要告訴你的provider的用戶,他們需要使用一個ContentResolver 的文件方法來操作數據。
3用大二進制對象 (BLOB)數據類型來存儲大小不定或沒有固定結構的數據。例如,你可以使用一個 BLOB列來存儲 協議緩沖 或 JSON 結構。
你也可以使用一個BLOB來實現一個獨立模式的表。在此種表中,你定義一個主鍵列,一個MIME類型列,和一個或多個普通的BLOB列。在 BLOB 列中的數據的意義由MIME列中的值所表明。這使你可以在一個表的各行中存儲不同類型的數據。聯系人Provider的"data"表ContactsContract.Data ,就是一個獨立模式表的例子。


 

設計內容URIs
 

一個內容URI 標志一個provider中的數據。內容URI包含了整個provider (他的 authority)的符號名和一個指向某個表或文件的名字。可選的id部分指向表中的一個獨立的行。ContentProvider 的每個數據操作方法具有一個內容URI作為一個參數;這允許你決定要操作的表,行或文件。
內容URI的基礎在標題Content Provider基礎 中被描述。


 

設計一個authority
 

一個provider通常具有單個authority,這作為它的安卓內部名字。為了避免與其它provider沖突,你應該使用互聯網域名方式取名 (不過是倒著的)來作為你的provider authority的基礎名字。因為此種建議也用於Android包的名字,所以你可以定義你的provider authority作為包含此provider的包名的擴展。 例如,如果你的Android包名是 com.example.<appname>,你應為你的provider authority命名為 com.example.<appname>.provider。


 

定義一個路徑結構
 

開發者通常通過添加指向獨立表的路徑來從authority 創建content URI。例如,如果你具有兩個表 table1和table2,你從前面例子中的authority 合並出來的內容 URI為 com.example.<appname>.provider/table1 和com.example.<appname>.provider/table2。路徑中並不限制只有一個參數,並且路徑的每一層也不是必須是一個表。


 

處理內容URI的 ID
 

為了方便,provider接受把一行的ID放在URI的尾部來提供對表中某一行的訪問。同樣為了方便,provider比較此 ID和表的_ID列,然後執行對匹配行的操作請求。.
這種方便性有助於在應用操作一個provider時使用一種通用的設計模式。應用向provider發出查詢然後在一個ListView 中使用一個CursorAdapter 顯示結果 Cursor 。CursorAdapter 的定義需要Cursor 中有一個列叫做 _ID 。
用戶之後就可以在UI中顯示的行中選擇一行進行查看或修改數據。app之後從ListView 背後的Cursor 中獲得相應的行,再獲得行的 _ID值,把此值添加到內容URI上,再把操作請求發送給provider。provider之後就執行查詢或修改用戶所指定的行。


 

內容URI的模式
 

為了幫你跟據到達的內容URI 選擇要執行的動作,provider API包含了簡便的類UriMatcher,它映射內容URI 的"模式" 到一個整數值。你可以在一個switch 語句中使用這個整數值來選擇為匹配一種模式的某個內容URI或多個URI們執行某種動作。
一個內容 URI使用通配符來匹配其它內容URI們:
*: 匹配任意長度的任意有效字符串。
#: 匹配由數字組成的任意長度的字符串。
看一個設計和編碼處理content URI的例子,假設一個provider其authority是 com.example.app.provider ,從它可以識別以下指向各表的內容URI:
1content://com.example.app.provider/table1: 一個叫table1 的表。
2content://com.example.app.provider/table2/dataset1: 一個叫dataset1 的表。
3content://com.example.app.provider/table2/dataset2: 一個叫dataset2 的表。
4content://com.example.app.provider/table3: 一個叫做table3 的表。
provider也識別那些具有一行的ID的內容URI,例如 content://com.example.app.provider/table3/1 指向表table3中的行1.
下面的內容 URI 模式也可能出現:
content://com.example.app.provider/*
匹配provider 中的任務內容URI。
content://com.example.app.provider/table2/*:
匹配表dataset1和表dataset2中的一個內容URI,但是不匹配table1或table3中的內容URI。
content://com.example.app.provider/table3/#: 匹配表 table3 中的任意一行,比如content://com.example.app.provider/table3/6 指向行6.
下面的代碼片段演示了UriMatcher 中的方法們如何工作。此代碼通過使用內容URI模式content://<authority>/<path> 指向表,用content://<authority>/<path>/<id> 指向一個單獨行,以不同的方式來處理指向整個表的 URI和指向單行的URI 。
方法addURI() 映射一個authority和路徑到一個整數值。方法android.content.UriMatcher#match(Uri) match()} 返回一個URI對應的整數值。一個switch 語句從查詢整個表和查詢單條記錄之間作出選擇:

 

  1. public class ExampleProvider extends ContentProvider {  
  2. ...  
  3.     // 創建一個UriMatcher對象  
  4.     private static final UriMatcher sUriMatcher;  
  5. ...  
  6.     /*  
  7.      * 到這裡,是對addURI()的調用。provider應能識別所有的內容URI的模式。  
  8.      * 但在此片段中,只演示對表3的調用。  
  9.      */ 
  10. ...  
  11.     /*  
  12.      * 映射表3中的多行模式為1 。注意路徑中沒有用通配符。  
  13.      */ 
  14.     sUriMatcher.addURI("com.example.app.provider", "table3", 1);  
  15.     /*  
  16.      * 映射單行模式為2 。 此例中,通配符"#"被使也。  
  17.      * "content://com.example.app.provider/table3/3" 能匹配此模式,但是  
  18.      * "content://com.example.app.provider/table3就不能了。  
  19.      */ 
  20.     sUriMatcher.addURI("com.example.app.provider", "table3/#", 2);  
  21. ...  
  22.     // 實現ContentProvider.query()  
  23.     public Cursor query(  
  24.         Uri uri,  
  25.         String[] projection,  
  26.         String selection,  
  27.         String[] selectionArgs,  
  28.         String sortOrder) {  
  29. ...  
  30.         /*  
  31.          * 選擇一個要查詢的表並跟據為輸入URI返回的代碼來選擇排序順序。  
  32.          * 這裡也是只演示表3 。  
  33.          */ 
  34.         switch (sUriMatcher.match(uri)) {  
  35.             // 如果輸入URI指向整個表3  
  36.             case 1:  
  37.                 if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";  
  38.                 break;  
  39.             // 如果輸入URI指向單行  
  40.             case 2:  
  41.                 /*  
  42.                  * 因為這個URI指向單行,所以_ID部分就出現了。  
  43.                  * 從URI獲取最後最後面的路徑段;它就是_ID值。  
  44.                  * 然後,添加這個值到查詢語句的WHERE子語句中。  
  45.                  */ 
  46.                 selection = selection + "_ID = " uri.getLastPathSegment();  
  47.                 break;  
  48.             default:  
  49.             ...  
  50.                 // 如果URI不能被識別,你應該在此處做一些錯誤處理。  
  51.         }  
  52.         // 調用進行實際查詢的代碼  
  53.     } 


 

另一個類,ContentUris, 提供處理內容URI中的id部分的簡便方法。類Uri 和 Uri.Builder 包含了分析已存在的Uri 對象和創建瓯新對象的簡便方法。

轉自:http://blog.csdn.net/nkmnkm/article/details/8088127

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved