Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android細筆記--ContentProvider,--contentprovider

Android細筆記--ContentProvider,--contentprovider

編輯:關於android開發

Android細筆記--ContentProvider,--contentprovider


Provider的不常見訪問方式

  • Batch access:訪問ContentProvider的一中模式,使用該模式可以同時對provider進行多個操作,且支持同時操作多個表。使用時首先構建一個ContentProviderOperation序列,然後使用ContentResolver.applyBatch方法把這些操作分發到provdier中,調用applyBatch參數時需要傳入provider的authority而不是某個表的Uri,這樣就可以使得不同的operation查詢不同的表。
  • 當你的應用A不具有訪問某個provider的權限時,你可以通過Intent的方法來訪問。典型的比如選擇一個聯系人,在A中可以發送一個Intent,設置相應的action和MIME類型,然後就會啟動比如聯系人應用來供用戶選擇一個聯系人,帶選擇完後,應用A的onActivityResult中就會收到返回的Intent,通過getData方法得到其中的Uri,這個Uri就指向了用戶選擇的聯系人,同時,在聯系人應用通過對返回的intent設置了FLAG_GRANT_READ_URI_PERMISSION以及FLAG_GRANT_WRITE_URI_PERMISSION兩個分別給接收該intent的Activity賦予臨時讀/寫該Uri指向的數據的權限,該權限直到該Activity finish之後就失效。另外一中方法就是通過發送Intent,並把需要的額外數據放入Intent中,然後交由另外一個具有該權限的應用去完成你想對該provider的操作。

用戶自定義MIME

  • 對於用戶自定義的,也稱作vendor-specific,的MIME類型,MIME類型的固定格式為type/subtype,對於自定的的MIME,其type固定為:對於多行:vnd.android.cursor.dir,對於單行為:vnd.android.cursor.item,而對於subtype類型則在遵守“vnd.<name>.<type>”形式的范圍內由用戶自定義。name必須全球唯一,一般為公司名或者報名,type則應該與URI類型有一對一的關系。例如對於一個authority為com.willhua.trains的provider,對應的表分別為list1和list2,那麼對於uri,content://com.willhua.trains/list1,其對應的MIME類型可以設定為vnd.android.cursor.dir/vnd.willhua.list1,對於uri,content://com.willhua.trains/list2/5,其對應的MIME類型可以設定為vnd.android.cursor.dir/vnd.willhua.list2。

設計數據結構tips

  • 最好有一個名為_ID的int列來作為primary key,這樣的話即可以把它當做foreign key來映射其他表中的數據,而且如果要把provider的查詢結果鏈入listview的,那麼就必須有_ID列(BaseColumns._ID;
  • 使用BOLB(binary large object)類型來存儲數據體積變化大或者數據結構不同的數據,比如protocol buffer或者JSON數據
  • 同樣可以使用BLOB來做一個schema-independent的表。一般來說,定一個int的primarykey,一個表示MIME類型的列,一個或者多個BLOB列,BLOB中的數據則可以根據MIME類型來解釋,這樣的話就實現了把不同shchema類型的數據存儲在了同一個表中,ConatactsContract.Data就是這樣一個例子的表。

URI

  • content Uri分成幾個部分,首先是開始的schema部分,即content://,這個都是一樣的;然後是provider的authority,ContentRsolver就是根據Uri這個部分匹配系統中已知的provider表而確定(resolver)需要使用哪個provider,從而調用相應provider的對於查詢方法;然後就是路徑或者表;最後就是若是表示單行的Uri則加上行ID。
  • 需要注意的是,路徑或者表部分沒有限定說只能有一個片段或者層級,比如content://com.willhua.blog/tablea/dataa/8或者content://com.willhua.blog/tablea/datab,這樣的Uri也是可以的,其中tablea/dataa和tablea/datab即表示路徑部分,且表示的表分別為dataa和datab,這樣的做法可以更好的顯示表的層級關系。
  • 在使用UriMatcher使用通配符判斷Uri類型時,符號‘*’表示任意長度的有效字符,‘#’表示任意長度的數字字符

ContentProvider的實現

  • query():對於查詢結果沒有任何匹配的項的時候應該返回getCount==0的cursor,而不是null。只有當查詢過程中發生錯誤才返回null。如果provider使用的數據存儲不是SQLite,那麼可以使用cursor的一些子類,比如MatrixCursor作為返回值。
  • insert():返回的值記得以該表的Uri然後append新插入行的ID.
  • delete():有時候可以考慮使用一個比如delete列來表示該行是否被刪除來代替真正的從表中刪除
  • update()
  • onCreate():應該盡可能的降低此函數的執行時間以提高響應速度。如果是使用SQLite作為數據存儲,那麼最好使用SQLiteOpenHelper,它將把創建SQL表的時候延遲到第一次打開database的時候。當第一次調用getWritableDatabase的時候,將調用Helper的onCreate函數。
  • getType():用於返回一個MIME格式的的字符串來描述根據content URI參數返回的數據類型。
  • getStreamTypes():如果provider提供files,那麼應該實現此函數。用於返回與content URI對應的MIME類型序列。例如某provider提供.jpg, .png兩種圖片,如果另一個應用調用getStreamTypes傳入的filter參數為“image/*”,那麼getStreamTypes應該返回{“image/jpg”, "image/png"}。如果沒有任何匹配該filter的,那麼返回null。

Provider權限控制

  • 對於放置在內部存儲器(internal)上的數據,默認是只能由本應用訪問的。但是如果把這些數據作為一個provider的倉庫的話,且在沒有對provider做額外的權限控制的條件下,那麼別的應用程序就可以通過provider完全訪問這些數據,也就是相當於把一個私有的數據完全開放了。這並不合理。所以,我們應該根據需要對provider進行一些訪問權限控制。
  • 對provider的權限設置可以分為三個級別:整個provider的完全權限,使用provider的android:permission控制,這個權限表示對整個provider的完全讀寫權限;單獨的讀或者寫權限,使用provider的android:readPermission和android:writePermission分別控制對整個provider的讀寫權限控制;路徑級別的權限控制,使用provider的子元素<path-permission>控制,可以控制針對某個具體的URI的讀寫,讀,寫或者三者的權限;
  • 這三個權限的優先級逐級增大,即假如某個數據同時被設定了整個provider的權限和path級別的權限,那麼外部應用就得必須有path級別的權限才能訪問這個數據。
  • 臨時權限,使用provider的android:grantUriPermission屬性(默認false)和子元素<grant-uri-permission>來分別控制對整個provider或者某個特定uri的臨時權限。具有臨時權限的訪問忽視前面說的三級權限要求。可以通過Content.revokeUriPermission()來收回針對某個uri的臨時權限。在Intent通過FLAG_GRANT_READ_URI_PERMISSION和FLAG_GRANT_WRITE_URI_PERMISSION來給別的應用分別賦予臨時讀寫權限。
  • 如果provider沒有指明所需的權限,那麼別的應用就無法訪問到這個provider。但是在provider所在應用中的其他組件是一直都是忽視所需權限要求的,有對該provider完整的讀寫權限。

 

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