苦心人天不負(fù)臥薪嘗膽三千越甲可吞吳,有志者天不負(fù)釜底抽薪百二秦川終屬楚。這是一對(duì)非常勵(lì)志的名言,每當(dāng)讀這句話(huà)都會(huì)被震撼一下,然后接著頹廢,哈哈,最近的工作比較忙,也在這里提醒自己,一定要堅(jiān)持下去,一定要堅(jiān)持一件對(duì)自己有益的事情。
裝逼到此進(jìn)入正題,今天要討論的主要內(nèi)容是ContentProvider(內(nèi)容提供者),ContentProvider也是android的四大組件之一,可見(jiàn)其在android中的重要性,可能大家用ContentProvider比其他三個(gè)組件用的少一點(diǎn),但是ContentProvider同樣的非常重要,有的人知道怎么使用ContentProvider,但是對(duì)于ContentProvider的原理等,并沒(méi)有搞清楚,沒(méi)關(guān)系,通過(guò)本篇博客相信你會(huì)對(duì)ContentProvider有一個(gè)全新的認(rèn)識(shí)。 通過(guò)本篇博客你將學(xué)到以下知識(shí) ①什么是內(nèi)容提供者 ②為什么會(huì)有內(nèi)容提供者 ③怎樣使用內(nèi)容提供者 ④ContentProvider中的Uri的詳細(xì)介紹 ⑤ContentResolver講解 ⑥UriMatch用法介紹 ⑦ContentObserver用法詳解 ⑧通過(guò)一個(gè)案例來(lái)講解自定義ContentProvider的執(zhí)行過(guò)程(下一篇將給大家?guī)?lái)調(diào)用系統(tǒng)的ContentProvider) 1.什么是內(nèi)容提供者? 首先我們必須要明白的是ContentProvider(內(nèi)容提供者)是android中的四大組件之一,但是在一般的開(kāi)發(fā)中,可能使用比較少。ContentProvider為不同的軟件之間數(shù)據(jù)共享,提供統(tǒng)一的接口。而且ContentProvider是以類(lèi)似數(shù)據(jù)庫(kù)中表的方式將數(shù)據(jù)暴露,也就是說(shuō)ContentProvider就像一個(gè)“數(shù)據(jù)庫(kù)”。那么外界獲取其提供的數(shù)據(jù),也就應(yīng)該與從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)的操作基本一樣,只不過(guò)是采用URI來(lái)表示外界需要訪問(wèn)的“數(shù)據(jù)庫(kù)”。至于如何從URI中識(shí)別出外界需要的是哪個(gè)“數(shù)據(jù)庫(kù)”這就是Android底層需要做的事情了,也就是說(shuō),如果我們想讓其他的應(yīng)用使用我們自己程序內(nèi)的數(shù)據(jù),就可以使用ContentProvider定義一個(gè)對(duì)外開(kāi)放的接口,從而使得其他的應(yīng)用可以使用我們自己應(yīng)用中的文件、數(shù)據(jù)庫(kù)內(nèi)存儲(chǔ)的信息。當(dāng)然,自己開(kāi)發(fā)的應(yīng)用需要給其他應(yīng)用共享信息的需求可能比較少見(jiàn),但是在Android系統(tǒng)中,很多數(shù)據(jù)如:聯(lián)系人信息、短信信息、圖片庫(kù)、音頻庫(kù)等,這些信息在開(kāi)發(fā)中還是經(jīng)常用到的,這些信息谷歌工程師已經(jīng)幫我們封裝好了,我們可以使用谷歌給我的Uri去直接訪問(wèn)這些數(shù)據(jù)。所以對(duì)于ContentProvider我們還是需要認(rèn)真的學(xué)習(xí)的,在遇到獲取聯(lián)系人信息,圖片庫(kù),音視頻庫(kù)等需求的時(shí)候,才能更好的實(shí)現(xiàn)功能。
2.為什么會(huì)有內(nèi)容提供者?
當(dāng)應(yīng)用繼承ContentProvider類(lèi),并重寫(xiě)該類(lèi)用于提供數(shù)據(jù)和存儲(chǔ)數(shù)據(jù)的方法,就可以向其他應(yīng)用共享其數(shù)據(jù)。雖然使用其他方法也可以對(duì)外共享數(shù)據(jù),但數(shù)據(jù)訪問(wèn)方式會(huì)因數(shù)據(jù)存儲(chǔ)的方式而不同,如:采用文件方式對(duì)外共享數(shù)據(jù),需要進(jìn)行文件操作讀寫(xiě)數(shù)據(jù);采用sharedpreferences共享數(shù)據(jù),需要使用sharedpreferences
API讀寫(xiě)數(shù)據(jù)。而使用ContentProvider共享數(shù)據(jù)的好處是統(tǒng)一了數(shù)據(jù)訪問(wèn)方式,這也是為什么會(huì)有內(nèi)容提供者的原因。
3.怎么使用內(nèi)容提供者?
在理解了什么是內(nèi)容提供者,為什么會(huì)有內(nèi)容提供者之后,我想在大家腦海中的浮現(xiàn)的一個(gè)問(wèn)題就是怎么使用內(nèi)容提供者,這也是今天我們要討論的重點(diǎn)內(nèi)容。在前面的博客我也說(shuō)到學(xué)習(xí)這種東西的最好方法是看谷歌給出的官方文檔,那么好我們先來(lái)翻譯一段谷歌給出的介紹(注:這是本地的文檔,我采用的是脫機(jī)工作地址(file:///D:/adt-bundle-windows-x86_64_20140101/sdk/docs/reference/android/content/ContentProvider.html))。
翻譯:
內(nèi)容提供者是android應(yīng)用程序的基本構(gòu)建塊之一,它們封裝數(shù)據(jù)并將封裝的數(shù)據(jù)通過(guò)單一的ContentResolver接口提供給應(yīng)用程序。當(dāng)你需要在多個(gè)應(yīng)用之間共享數(shù)據(jù)的時(shí)候就需要用到內(nèi)容提供者。例如,手機(jī)中的聯(lián)系人數(shù)據(jù)會(huì)被多個(gè)應(yīng)用所用到所以必須要用內(nèi)容提供者存儲(chǔ)起來(lái)。如果你不需要在多個(gè)應(yīng)用之間共享數(shù)據(jù),你可以使用一個(gè)數(shù)據(jù)庫(kù),直接通過(guò)SQLite數(shù)據(jù)庫(kù)。 當(dāng)通過(guò)content resolver發(fā)送一個(gè)請(qǐng)求時(shí),系統(tǒng)會(huì)檢查給定的URI并把請(qǐng)求傳給有注冊(cè)授權(quán)的Contentprovider。 UriMatcher類(lèi)有助于解析uri。
需要實(shí)現(xiàn)的主要方法是:
public boolean onCreate()
在創(chuàng)建ContentProvider時(shí)調(diào)用
public Cursor query(Uri,
String[], String, String[], String) 用于查詢(xún)指定Uri的ContentProvider,返回一個(gè)Cursor
public Uri insert(Uri,
ContentValues) 用于添加數(shù)據(jù)到指定Uri的ContentProvider中,(外部應(yīng)用向ContentProvider中添加數(shù)據(jù))
public int update(Uri,
ContentValues, String, String[]) 用于更新指定Uri的ContentProvider中的數(shù)據(jù)
public int delete(Uri,
String, String[]) 用于從指定Uri的ContentProvider中刪除數(shù)據(jù)
public String getType(Uri)
用于返回指定的Uri中的數(shù)據(jù)的MIME類(lèi)型
數(shù)據(jù)訪問(wèn)的方法(如:insert(Uri, ContentValues) and update(Uri, ContentValues, String, String[]))可能被多個(gè)線程同時(shí)調(diào)用,此時(shí)必須是線程安全的。其他方法(如:
onCreate())只能被應(yīng)用的主線程調(diào)用,它應(yīng)當(dāng)避免冗長(zhǎng)的操作。ContentResolver(內(nèi)容解析者)請(qǐng)求被自動(dòng)轉(zhuǎn)發(fā)到合適的內(nèi)容提供者實(shí)例,所以子類(lèi)不需要擔(dān)心跨進(jìn)程調(diào)用的細(xì)節(jié)。
唉,每次最頭疼的就是看全英文的文檔,發(fā)現(xiàn)自己的英語(yǔ)水平太差,最近也在空閑時(shí)間學(xué)習(xí)學(xué)習(xí)英語(yǔ),但是對(duì)于英語(yǔ)從來(lái)就沒(méi)感興趣過(guò),希望自己可以堅(jiān)持一段時(shí)間吧,其實(shí)在開(kāi)發(fā)過(guò)程中遇到那些比較難解決的問(wèn)題,在國(guó)外的有名的網(wǎng)站中基本都是可以查找到的,但是對(duì)于我這樣一個(gè)英語(yǔ)水平差的人來(lái)說(shuō),說(shuō)多了其實(shí)都是眼淚。。。,我先哭一會(huì)。。。
關(guān)于怎樣使用ContentProvider后面有實(shí)例幫助大家理解。4.Uri詳解
在上面的翻譯中如果你認(rèn)真看的話(huà)你會(huì)發(fā)現(xiàn)在谷歌的官方文檔中提到了ContentResolver(內(nèi)容解析者),外界可以通過(guò)ContentResolver接口來(lái)訪問(wèn)ContentProvider(內(nèi)容提供者)中的數(shù)據(jù)。但是在詳細(xì)了解ContentResolver之前有一項(xiàng)工作是必須要做的,那就是先理解Uri,在谷歌文檔中也有介紹,接下來(lái)我們就來(lái)詳細(xì)的學(xué)習(xí)下Uri這個(gè)類(lèi)
Uri 通用資源標(biāo)志符(Universal Resource Identifier)Uri代表要操作的數(shù)據(jù),Android中可用的每種資源 - 圖像、視頻片段等都可以用Uri來(lái)表示。Uri的結(jié)構(gòu)由以下幾個(gè)部分組成
scheme、authority、path、query和fragment組成。其中authority又分為host和port。它的格式根據(jù)劃分的詳細(xì)程度可以分為三種
如下:
[scheme:][scheme-specific-part][#fragment]
[scheme:][//authority][path][?query][#fragment]
[scheme:][//host:port][path][?query][#fragment]——最詳細(xì)的劃分形式
看到這里肯定有人糊里糊涂的,接著我們就來(lái)舉一個(gè)例子來(lái)幫助大家詳細(xì)的理解Uri這個(gè)類(lèi)的結(jié)構(gòu)
假如有這么一個(gè)Uri:http://www.baidu.com:8080/yourpath/fileName.html?id=15&name=du#dmk
你能將上述Uri進(jìn)行提取嗎?接著我們就比著標(biāo)準(zhǔn)的格式[scheme:][//host:port][path][?query][#fragment]來(lái)將這個(gè)Uri各個(gè)部分提取出來(lái)
scheme:根據(jù)標(biāo)準(zhǔn)格式可以看出這里的scheme就是Uri前面//前面的部分這里也就是http:。
fragment:dmk這個(gè)也是比較容易找到的,在#后面
query:id=15&name=du#dmk。從標(biāo)準(zhǔn)格式可以看到在"#"之前"?"之后的部分是query,在這里當(dāng)然就是id=15&name=du#dmk了。
authority:從格式二中可以看到authority是在//后的部分,它的終點(diǎn)就是在path之前所以這里的authority就是www.baidu.com:8080
path:path就是?之前,主機(jī)之后的部分那就是yourpath/fileName.html
這里要提醒大家注意的是:在Uri中并不是上述所有的字段都必須有的除了scheme、authority是必須要有的,其它的幾個(gè)path、query、fragment,它們每一個(gè)可以選擇性的要或不要,但順序不能變,比方說(shuō)在上述Uri中沒(méi)有path那它的格式就為:http://www.baidu.com:8080/?id=15&name=du#dmk。
在理解了Uri的格式之后,有的人可能會(huì)說(shuō)Uri的各個(gè)字段能否用代碼獲???答案是肯定的
到這里關(guān)于Uri的介紹就完了(這里的關(guān)于Uri的介紹的內(nèi)容主要來(lái)自:Uri詳解之——Uri結(jié)構(gòu)與代碼提取 和 Java魔法堂:URI、URL(含URL
Protocol Handler)
5.ContentResolver講解
在了解了Uri之后就可以來(lái)學(xué)習(xí)學(xué)習(xí)ContentResolver了,前面我們說(shuō)到ContentProvider共享數(shù)據(jù)是通過(guò)定義一個(gè)對(duì)外開(kāi)放的統(tǒng)一的接口來(lái)實(shí)現(xiàn)的。然而,應(yīng)用程序并不直接調(diào)用這些方法,而是使用一個(gè)
ContentResolver 對(duì)象,調(diào)用它的方法作為替代。ContentResolver可以與任意內(nèi)容提供者進(jìn)行會(huì)話(huà),與其合作來(lái)對(duì)所有相關(guān)交互通訊進(jìn)行管理。當(dāng)外部應(yīng)用需要對(duì)ContentProvider中的數(shù)據(jù)進(jìn)行添加、刪除、修改和查詢(xún)操作時(shí),可以使用ContentResolver類(lèi)來(lái)完成,要獲取ContentResolver對(duì)象,可以使用Context提供的getContentResolver()方法。ContentResolver cr = getContentResolver();在上面我們提到ContentProvider可以向其他應(yīng)用程序提供數(shù)據(jù),與之對(duì)應(yīng)的ContentResolver則負(fù)責(zé)獲取ContentProvider提供的數(shù)據(jù),修改、添加、刪除更新數(shù)據(jù)等;
ContentResolver 類(lèi)也提供了與ContentProvider類(lèi)相對(duì)應(yīng)的四個(gè)方法:
public Uri insert(Uri uri, ContentValues values) 該方法用于往ContentProvider添加數(shù)據(jù)。
public int delete(Uri uri, String selection, String[] selectionArgs) 該方法用于從ContentProvider刪除數(shù)據(jù)。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 該方法用于更新ContentProvider中的數(shù)據(jù)。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 該方法用于從ContentProvider中獲取數(shù)據(jù)。
這些方法的第一個(gè)參數(shù)為Uri,代表要操作的是哪個(gè)ContentProvider和對(duì)其中的什么數(shù)據(jù)進(jìn)行操作,假設(shè)給定的是 Uri.parse(“content://com.qstingda.provider.personprovider/contact/15”),那么將會(huì)對(duì)主機(jī)名為com.qstingda.provider.personprovider的ContentProvider進(jìn)行操作,path為contact/15的數(shù)據(jù),看到這如果你之前沒(méi)有接觸過(guò)ContentProvider肯定一頭霧水,沒(méi)有關(guān)系,這很正常,等我們把理論知識(shí)講完后會(huì)有實(shí)例,相信你看過(guò)實(shí)例后就會(huì)很明白了。
6.UriMatch
UriMatcher 類(lèi)主要用于匹配Uri.這里的匹配是發(fā)生在ContentProvider中的,假如我們向ContentProvider中插入一條數(shù)據(jù),不可能為所欲為的想怎么干就怎么干,在ContentProvider肯定要做一個(gè)判斷,只有在符合條件下才會(huì)去執(zhí)行你想要執(zhí)行的操作,這里的判斷就是用UriMatch進(jìn)行匹配,假如是系統(tǒng)的ContentProvider如聯(lián)系人、圖庫(kù)、視頻庫(kù)等,這些系統(tǒng)都提供了Uri我們可以根據(jù)系統(tǒng)提供的Uri來(lái)操作相應(yīng)的數(shù)據(jù)。其實(shí)UriMatch的用法非常簡(jiǎn)單,查閱谷歌官方文檔你會(huì)發(fā)現(xiàn)有這么幾個(gè)方法
①publicUriMatcher(int
code) 它的作用就是創(chuàng)建一個(gè)UriMatch對(duì)象
它的作用是在ContentProvider添加一個(gè)用于匹配的Uri,當(dāng)匹配成功時(shí)返回code。Uri可以是精確的字符串,Uri中帶有*表示可匹配任意text,#表示只能匹配數(shù)字。 ③public int match(Uri uri) 這里的Uri就是傳過(guò)來(lái)的要進(jìn)行驗(yàn)證,匹配的Uri假如傳過(guò)來(lái)的是:content://com.example.test/student/#,則content://com.example.test/student/10可以匹配成功,這里的10可以使任意的數(shù)字。 7.ContentObserver用法
ContentObserver——內(nèi)容觀察者,從其名字我們可以看出它的作用就是觀察,觀察什么?觀察指定的Uri引起的數(shù)據(jù)庫(kù)的變化,然后通知主線程,根據(jù)需求做我們想要做的處理。這樣說(shuō)大家可能理解的不是特別透徹,這樣跟大家說(shuō)它可以實(shí)現(xiàn)類(lèi)似于Adapter的notifyDataSetChanged()這個(gè)方法的作用,比方說(shuō)當(dāng)觀察到ContentProvider的數(shù)據(jù)變化時(shí)會(huì)自動(dòng)調(diào)用谷歌工程師給我們提供的好的方法,可以在此方法中通知主線程數(shù)據(jù)改變等等。那么問(wèn)題來(lái)了,應(yīng)該怎樣實(shí)現(xiàn)這樣的功能呢?首先要做的就是注冊(cè)這個(gè)觀察者,這里的注冊(cè)是在需要監(jiān)測(cè)ContentProvider的應(yīng)用中進(jìn)行注冊(cè)并不是在ContentProvider中而在ContentProvider中要做的就是當(dāng)數(shù)據(jù)變化時(shí)進(jìn)行通知,這里的通知的方法谷歌已經(jīng)幫我們寫(xiě)好,直接調(diào)用就行了,查看谷歌文檔你會(huì)發(fā)現(xiàn)在ContentResolver中有這樣的介紹:
public final void registerContentObserver (Uri uri, boolean notifyForDescendents, ContentObserver observer) 注冊(cè)一個(gè)觀察者實(shí)例,當(dāng)指定的Uri發(fā)生改變時(shí),這個(gè)實(shí)例會(huì)回調(diào)實(shí)例對(duì)象做相應(yīng)處理。 參數(shù):uri:需要觀察的Uri notifyForDescendents:如果為true表示以這個(gè)Uri為開(kāi)頭的所有Uri都會(huì)被匹配到, 如果為false表示精確匹配,即只會(huì)匹配這個(gè)給定的Uri。 舉個(gè)例子,假如有這么幾個(gè)Uri: ①content://com.example.studentProvider/student ②content://com.example.studentProvider/student/# ③content://com.example.studentProvider/student/10 ④content://com.example.studentProvider/student/teacher 假如觀察的Uri為content://com.example.studentProvider/student,當(dāng)notifyForDescendents為true時(shí)則以這個(gè)Uri開(kāi)頭的Uri的數(shù)據(jù)變化時(shí)都會(huì)被捕捉到,在這里也就是①②③④的Uri的數(shù)據(jù)的變化都能被捕捉到,當(dāng)notifyForDescendents為false時(shí)則只有①中Uri變化時(shí)才能被捕捉到。 看到registerContentObserver 這個(gè)方法,根據(jù)語(yǔ)言基礎(chǔ)我想大家能夠想到ContentResolver中的另一個(gè)方法 public final voidunregisterContentObserver(ContentObserverobserver)它的作用就是取消對(duì)注冊(cè)的那個(gè)Uri的觀察,這里傳進(jìn)去的就是在registerContentObserver中傳遞進(jìn)去的ContentObserver對(duì)象。到這關(guān)于注冊(cè)和解除注冊(cè)的ContentObserver可能大家都比較清楚了,那么問(wèn)題來(lái)了,怎么去寫(xiě)一個(gè)ContentObserver呢?其實(shí)它的實(shí)現(xiàn)很簡(jiǎn)單,直接創(chuàng)建一個(gè)類(lèi)繼承ContentObserver需要注意的是這里必須要實(shí)現(xiàn)它的構(gòu)造方法 public ContentObserver(Handlerhandler) 這里傳進(jìn)去的是一個(gè)Handler對(duì)象,這個(gè)Handler對(duì)象的作用一般要依賴(lài)于ContentObserver的另一個(gè)方法即
public void onChange(boolean selfChange) 這個(gè)方法的作用就是當(dāng)指定的Uri的數(shù)據(jù)發(fā)生變化時(shí)會(huì)回調(diào)該方法,此時(shí)可以借助構(gòu)造方法中的Handler對(duì)象將這個(gè)變化的消息發(fā)送給主線程,當(dāng)主線程接收到這個(gè)消息之后就可以按照我們的需求來(lái)完成相應(yīng)的操作,比如上面提到的類(lèi)似于Adapter的notifyDataSetChanged()的作用,下面的案例也是完成了這個(gè)功能,準(zhǔn)備工作完成之后來(lái)看一個(gè)案例,相信這個(gè)案例會(huì)讓你對(duì)以上知識(shí)了解的更加深入。 在真正的開(kāi)發(fā)中我們很少去自定義一個(gè)ContentProvider因?yàn)镃ontentProvider是為了更好的去共享數(shù)據(jù),我們?cè)陂_(kāi)發(fā)中很少會(huì)遇到這種情況,而遇到更多的則是訪問(wèn)系統(tǒng)的ContentProvider,系統(tǒng)的ContentProvider谷歌工程師已經(jīng)幫我們寫(xiě)好了,我們直接使用就可以了,這里為了讓大家能夠理解ContentProvider更加徹底,我們自定義一個(gè)ContentProvider然后在其它應(yīng)用中來(lái)訪問(wèn)自定義的ContentProvider的數(shù)據(jù)這個(gè)案例的運(yùn)行效果如下:
這里的插入數(shù)據(jù),是在一個(gè)項(xiàng)目中向另一個(gè)項(xiàng)目中的ContentProvider中插入一條數(shù)據(jù),其他的操作也是,接下來(lái)就來(lái)看看怎么實(shí)現(xiàn)上述的效果。
在上面我們提到在自定義ContentProvider時(shí)需要繼承ContentProvider并實(shí)現(xiàn)3中所述的那幾個(gè)方法(系統(tǒng)會(huì)自動(dòng)幫你將要復(fù)寫(xiě)的方法羅列出來(lái)),那么我們自定義的PeopleContentProvider的代碼如下
可以看到在onCreate()方法中創(chuàng)建了一個(gè)數(shù)據(jù)庫(kù),關(guān)于數(shù)據(jù)庫(kù)的操作大家可以看此博客http://blog.csdn.net/dmk877/article/details/44876805。這里就不多做介紹了。注意這個(gè)案例牽扯到兩個(gè)項(xiàng)目,一個(gè)是包含我們自定義的ContentProvider,另一個(gè)項(xiàng)目是訪問(wèn)這個(gè)包含ContentProvider項(xiàng)目中的數(shù)據(jù)。寫(xiě)好PeopleContentProvider之后千萬(wàn)不要忘了在清單文件中注冊(cè)
這里的authorities就是它是唯一標(biāo)識(shí)內(nèi)容提供者的,為內(nèi)容提供者指定一個(gè)唯一的標(biāo)識(shí),這樣別的應(yīng)用才可以唯一獲取此provider,exported的值為[flase|true]當(dāng)為true時(shí):當(dāng)前提供者可以被其它應(yīng)用使用。任何應(yīng)用可以使用Provider通過(guò)URI
來(lái)獲得它,也可以通過(guò)相應(yīng)的權(quán)限來(lái)使用Provider。當(dāng)為false時(shí):當(dāng)前提供者不能被其它應(yīng)用使用,默認(rèn)為true。注冊(cè)好之后運(yùn)行到手機(jī)上,此時(shí)其它的應(yīng)用就可以通過(guò)ContentResolver來(lái)訪問(wèn)這個(gè)PeopleContentProvider了,具體怎么操作呢?我們再新建一個(gè)項(xiàng)目在MainActivity的代碼如下:
可以看出若想操作我們想操作的ContentProvider,必須要知道內(nèi)容提供者的Uri,再正確得到Uri之后,就可以通過(guò)ContentResolver對(duì)象來(lái)操作ContentProvider中的數(shù)據(jù)了,假如你需要插入數(shù)據(jù)只需要調(diào)用contentResolver.insert(uri, contentValues);把正確的uri和ContentValues鍵值對(duì)傳過(guò)去就行了。執(zhí)行這句話(huà)系統(tǒng)就會(huì)根據(jù)我們提供的uri找到對(duì)應(yīng)的ContentProvider,因?yàn)槲覀兊膗ri中包含了authority(主機(jī)等各種信息),得到對(duì)應(yīng)的ContentProvider后將調(diào)用ContentResolver的與之對(duì)應(yīng)的增刪改查方法,并將參數(shù)通過(guò)ContentResolver的增刪改查方法傳遞到ContentProvider中。在上面用到了CursorAdapter關(guān)于CursorAdapter的用法可以參考此博客http://blog.csdn.net/dmk877/article/details/44983491
PersonObserver的代碼如下
可以看到,在構(gòu)造方法中接收了Handler然后當(dāng)監(jiān)聽(tīng)到指定的Uri的數(shù)據(jù)變化時(shí)就會(huì)通過(guò)Handler消息機(jī)制發(fā)送一條消息,然后的操作就由我們自行完成了。到這里我們來(lái)理一理整個(gè)操作的運(yùn)行流程:首先有兩個(gè)項(xiàng)目,一個(gè)是有ContentProvider的,在這個(gè)ContentProvider中初始化了一個(gè)數(shù)據(jù)庫(kù),我們的目的就是在另一個(gè)項(xiàng)目中來(lái)操作這個(gè)項(xiàng)目中ContentProvider中的數(shù)據(jù),例如插入一條數(shù)據(jù),查詢(xún)等。對(duì)于怎么在另一個(gè)項(xiàng)目中操作ContentProvider中的數(shù)據(jù),是通過(guò)ContentResolver(內(nèi)容解析者)對(duì)象來(lái)操作的,假如我們要進(jìn)行insert操作,那么需要調(diào)用ContentResolver的insert(uri,
ContentValues);將Uri和ContentValues對(duì)象經(jīng)過(guò)一系列操作傳遞到ContentProvider的中,然后在ContentProvider會(huì)對(duì)這個(gè)Uri進(jìn)行匹配,如果匹配成功則按照我們的需求去執(zhí)行相應(yīng)的操作,如:插入數(shù)據(jù)、查詢(xún)數(shù)據(jù)等。如果想進(jìn)一步理解ContentProvider和ContentResolver之間的關(guān)系http://blog.csdn.net/u010961631/article/details/14227421(對(duì)這個(gè)過(guò)程從源碼進(jìn)行了解析,不建議初學(xué)者閱讀)。下面我們來(lái)畫(huà)一張圖再來(lái)說(shuō)一下這個(gè)過(guò)程
從圖中可以看出在OtherApplication中注冊(cè)了ContentObserver之后,當(dāng)Application1中的數(shù)據(jù)庫(kù)發(fā)生了變化時(shí),只需要在ContentProvider中調(diào)用ContentResolver的notifyChange(Uri,ContentObserver
observer),由于在OtherApplication中注冊(cè)了ContentObserver(注冊(cè)時(shí)用的Uri和ContentProvider中發(fā)生變化的Uri一樣)因此在ContentObserver中會(huì)收到這個(gè)變化信息,它就可以將這個(gè)消息通過(guò)Handler發(fā)送給OtherApplication。 |
|