Android
的四大組件之一,ContentProvider
能夠說是無處不在了。ContentProvider
用得很嫺熟,卻一直沒能造成一個完整的體系。ContentProvider
。最後,但願你們閱讀愉快!java
ContentProvider
應用程序間很是通用的共享數據的一種方式,也是 Android
官方推薦的方式。Android
中許多系統應用都使用該方式實現數據共享,好比通信錄、短信等。倉庫內容與博客同步更新。因爲我在 稀土掘金
簡書
CSDN
博客園
等站點,都有新內容發佈。因此你們能夠直接關注該倉庫,以避免錯過精彩內容!android
Android
開發的人都不怎麼使用它,以爲直接讀取數據庫會更簡單方便。Android
搞一個內容提供者在數據和應用之間,只是爲了裝高大上,故弄玄虛?我認爲其設計用意在於:DB
,XML
、Preferences
或者網絡請求來的。當項目需求要改變數據來源時,使用咱們的地方徹底不須要修改。ContentResolver
接口的 notifyChange
函數來通知那些註冊了監控特定 URI的ContentObserver 對象,使得它們能夠相應地執行一些處理。ContentProvider
的 Uri
訪問開放的數據。ContenResolver
對象經過 Context
提供的方法 getContenResolver()
來得到。ContenResolver
提供瞭如下方法來操做:insert
delete
update
query
這些方法分別會調用 ContenProvider
中與之對應的方法並獲得返回的結果。ContentResolver
類對象:ContentResolver cr = getContentResolver ( )
。String
數組。cr.query()
; 返回一個 Cursor
對象。while
循環獲得 Cursor
裏面的內容。Android
中若是想將本身應用的數據 ( 通常多爲數據庫中的數據 ) 提供給第三發應用, 那麼咱們只能經過 ContentProvider
來實現了。 ContentProvider
是應用程序之間共享數據的接口。ContentProvider
, 而後覆寫 query
、insert
、update
、delete
等 方法。AndroidManifest
文件中進行註冊。uri
的形式共享出去 android
系統下 不一樣程序 數據默認是不能共享訪問 須要去實現一個類去繼承 ContentProvider
。public class PersonContentProvider extends ContentProvider{ public boolean onCreate(){ } query(Url, String[], String, String[], String); insert(Uri,ContentValues); update(Uri,ContentValues,String[]); delete(Uri,String,String[]); }
ContentProvider
屏蔽了數據存儲的細節 , 內部實現對用戶徹底透明 , 用戶只須要關心操做數據的 uri
就能夠了, ContentProvider
能夠實現不一樣 app
之間 共享。Sql
也有增刪改查的方法, 可是 sql
只能查詢本應用下的數據庫。ContentProvider
還能夠去增刪改查本地文件. xml
文件的讀取等。ContentProvider
都擁有一個公共的 URI
,這個 URI
用於表示這個 ContentProvider
所提供的數據。Android
所提供的 ContentProvider
都存放在 android.provider
包中。A,B,C,D
4個部分:A
:標準前綴,用來講明一個 Content Provider
控制這些數據,沒法改變的;"content://"
;B
:URI
的標識,用於惟一標識這個 ContentProvider
,外部調用者能夠根據這個標識來找到它。它定義了是哪一個 ContentProvider
提供這些數據。對於第三方應用程序,爲了保證 URI
標識的惟一性,它必須是一個完整的、小寫的類名。這個標識在元素的 authorities
屬性中說明:通常是定義該 ContentProvider
的包類的名稱;C
:路徑( path
),通俗的講就是你要操做的數據庫中表的名字,或者你也能夠本身定義,記得在使用的時候保持一致就能夠了;"content://com.bing.provider.myprovider/tablename"
。D
:若是URI中包含表示須要獲取的記錄的 ID
;則就返回該id對應的數據,若是沒有 ID
,就表示返回所有; "content://com.bing.provider.myprovider/tablename/#"
#
表示數據 id
。db
複製到 /data/data/packagename/databases/
目錄下, 而後直接就能訪問了。ContentProvider
能夠接受來自另一個進程的數據請求。ContentResolver
與 ContentProvider
類隱藏了實現細節,可是 ContentProvider
所提供的 query()
,insert()
,delete()
,update()
都是在 ContentProvider
進程的線程池中被調用執行的,而不是進程的主線程中。Binder
建立和維護的,其實使用的就是每一個應用進程中的 Binder
線程池。ContentProvider
能夠對開發的數據進行權限設置,不一樣的 URI
能夠對應不一樣的權限,只有符合權限要求的組件才能訪問到 ContentProvider
的具體操做。ContentProvider
封裝了跨進程共享的邏輯,咱們只須要 Uri
便可訪問數據。由系統來管理 ContentProvider
的建立、生命週期及訪問的線程分配,簡化咱們在應用間共享數據( 進程間通訊 )的方式。咱們只管經過 ContentResolver
訪問 ContentProvider
所提示的數據接口,而不須要擔憂它所在進程是啓動仍是未啓動。ContentProvider
的 onCreate()
是運行在 UI
線程的,而 query()
,insert()
,delete()
,update()
是運行在線程池中的工做線程的ContentProvider
所在進程的主線程,但可能會阻塞調用者所在的進程的 UI
線程!ContentProvider
的操做仍然要放在子線程中去作。CRUD
的操做是在工做線程的,但系統會讓你的調用線程等待這個異步的操做完成,你才能夠繼續線程以前的工做。android:exported
屬性很是重要。這個屬性用於指示該服務是否可以被其餘應用程序組件調用或跟它交互。true
,則可以被調用或交互,不然不能。設置爲 false
時,只有同一個應用程序的組件或帶有相同用戶 ID
的應用程序才能啓動或綁定該服務。github
ContentProvider
,則能夠設置 signature
級別的權限。你們能夠參考一下系統自帶應用的代碼,自定義了 signature
級別的 permission
:web
<permission android:name="com.android.gallery3d.filtershow.permission.READ" android:protectionLevel="signature" /> <permission android:name="com.android.gallery3d.filtershow.permission.WRITE" android:protectionLevel="signature" /> <provider android:name="com.android.gallery3d.filtershow.provider.SharedImageProvider" android:authorities="com.android.gallery3d.filtershow.provider.SharedImageProvider" android:grantUriPermissions="true" android:readPermission="com.android.gallery3d.filtershow.permission.READ" android:writePermission="com.android.gallery3d.filtershow.permission.WRITE" />
URI
給其餘的應用訪問呢?Provider
的 URI
權限設置,只容許訪問部份 URI
,能夠參考原生 ContactsProvider2
的相關代碼( 注意 path-permission
這個選項 ):<provider android:name="ContactsProvider2" android:authorities="contacts;com.android.contacts" android:label="@string/provider_label" android:multiprocess="false" android:exported="true" android:grantUriPermissions="true" android:readPermission="android.permission.READ_CONTACTS" android:writePermission="android.permission.WRITE_CONTACTS"> <path-permission android:pathPrefix="/search_suggest_query" android:readPermission="android.permission.GLOBAL_SEARCH" /> <path-permission android:pathPrefix="/search_suggest_shortcut" android:readPermission="android.permission.GLOBAL_SEARCH" /> <path-permission android:pathPattern="/contacts/.*/photo" android:readPermission="android.permission.GLOBAL_SEARCH" /> <grant-uri-permission android:pathPattern=".*" /> </provider>
ContentProvider
能夠在 AndroidManifest.xml
中配置一個叫作 android:multiprocess
的屬性,默認值是 false ,表示 ContentProvider 是單例的ContentProvider
對象,若是設爲 true
,系統會爲每個訪問該 ContentProvider
的進程建立一個實例。好比咱們在UI線程調用getContentResolver().query查詢數據,而當數據量很大時(或者須要進行較長時間的計算)會不會阻塞UI線程呢?面試
要分兩種狀況回答這個問題:算法
ContentProvider
和調用者在同一個進程,ContentProvider
的方法( query/insert/update/delete
等 )和調用者在同一線程中;ContentProvider
和調用者在不一樣的進程,ContentProvider
的方法會運行在它自身所在進程的一個 Binder 線程中。ContentProvider
的方法沒有執行完成前都會 blocked
調用者。因此你應該知道這個上面這個問題的答案了吧。CursorLoader
這個類的源碼,看 Google
本身是怎麼使用 getContentResolver().query
的。16
個 Binder
線程去和遠程服務進行交互,而每一個線程可佔用的緩存空間是 128KB
這樣,超過會報異常。ContentResolver
雖然是經過 Binder
進程間通訊機制打通了應用程序之間共享數據的通道,但 ContentProvider
組件在不一樣應用程序之間傳輸數據是基於匿名共享內存機制來實現的。BroadcastReceiver
知識總進行了詳細的總結,但願你們經過本次閱讀都能有所收穫。重點
:學 Android
有一段時間了,我打算好好的梳理一下所學知識,到如今爲止,我才總結完 Activity
、Service
、BroadcastRecevier
等,有關 事件分發、滑動衝突、新能優化等重要模塊,我後面也將詳盡的總結,歡迎你們關注 _yuanhao 的 博客園 ,方便及時接收更新因爲我在「稀土掘金」「簡書」「CSDN
」「博客園」等站點,都有新內容發佈。因此你們能夠直接關注個人 GitHub
倉庫,以避免錯過精彩內容!sql
一萬多字長文,加上精美思惟導圖,記得點贊哦,歡迎關注 _yuanhao 的 博客園 ,咱們下篇文章見!數組