免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Android開發(fā)之內(nèi)容提供者-創(chuàng)建自己的ContentProvider(詳解)

苦心人天不負(fù)臥薪嘗膽三千越甲可吞吳,有志者天不負(fù)釜底抽薪百二秦川終屬楚。這是一對非常勵志的名言,每當(dāng)讀這句話都會被震撼一下,然后接著頹廢,哈哈,最近的工作比較忙,也在這里提醒自己,一定要堅持下去,一定要堅持一件對自己有益的事情。

 

裝逼到此進(jìn)入正題,今天要討論的主要內(nèi)容是ContentProvider(內(nèi)容提供者),ContentProvider也是android的四大組件之一,可見其在android中的重要性,可能大家用ContentProvider比其他三個組件用的少一點,但是ContentProvider同樣的非常重要,有的人知道怎么使用ContentProvider,但是對于ContentProvider的原理等,并沒有搞清楚,沒關(guān)系,通過本篇博客相信你會對ContentProvider有一個全新的認(rèn)識。

通過本篇博客你將學(xué)到以下知識

①什么是內(nèi)容提供者

②為什么會有內(nèi)容提供者

③怎樣使用內(nèi)容提供者

④ContentProvider中的Uri的詳細(xì)介紹

⑤ContentResolver講解

UriMatch用法介紹

⑦ContentObserver用法詳解

⑧通過一個案例來講解自定義ContentProvider的執(zhí)行過程(下一篇將給大家?guī)碚{(diào)用系統(tǒng)的ContentProvider)


1.什么是內(nèi)容提供者?

     首先我們必須要明白的是ContentProvider(內(nèi)容提供者)是android中的四大組件之一,但是在一般的開發(fā)中,可能使用比較少。ContentProvider為不同的軟件之間數(shù)據(jù)共享,提供統(tǒng)一的接口。而且ContentProvider是以類似數(shù)據(jù)庫中表的方式將數(shù)據(jù)暴露,也就是說ContentProvider就像一個“數(shù)據(jù)庫”。那么外界獲取其提供的數(shù)據(jù),也就應(yīng)該與從數(shù)據(jù)庫中獲取數(shù)據(jù)的操作基本一樣,只不過是采用URI來表示外界需要訪問的“數(shù)據(jù)庫”。至于如何從URI中識別出外界需要的是哪個“數(shù)據(jù)庫”這就是Android底層需要做的事情了,也就是說,如果我們想讓其他的應(yīng)用使用我們自己程序內(nèi)的數(shù)據(jù),就可以使用ContentProvider定義一個對外開放的接口,從而使得其他的應(yīng)用可以使用我們自己應(yīng)用中的文件、數(shù)據(jù)庫內(nèi)存儲的信息。當(dāng)然,自己開發(fā)的應(yīng)用需要給其他應(yīng)用共享信息的需求可能比較少見,但是在Android系統(tǒng)中,很多數(shù)據(jù)如:聯(lián)系人信息、短信信息、圖片庫、音頻庫等,這些信息在開發(fā)中還是經(jīng)常用到的,這些信息谷歌工程師已經(jīng)幫我們封裝好了,我們可以使用谷歌給我的Uri去直接訪問這些數(shù)據(jù)。所以對于ContentProvider我們還是需要認(rèn)真的學(xué)習(xí)的,在遇到獲取聯(lián)系人信息,圖片庫,音視頻庫等需求的時候,才能更好的實現(xiàn)功能。


2.為什么會有內(nèi)容提供者?
       當(dāng)應(yīng)用繼承ContentProvider類,并重寫該類用于提供數(shù)據(jù)和存儲數(shù)據(jù)的方法,就可以向其他應(yīng)用共享其數(shù)據(jù)。雖然使用其他方法也可以對外共享數(shù)據(jù),但數(shù)據(jù)訪問方式會因數(shù)據(jù)存儲的方式而不同,如:采用文件方式對外共享數(shù)據(jù),需要進(jìn)行文件操作讀寫數(shù)據(jù);采用sharedpreferences共享數(shù)據(jù),需要使用sharedpreferences API讀寫數(shù)據(jù)。而使用ContentProvider共享數(shù)據(jù)的好處是統(tǒng)一了數(shù)據(jù)訪問方式,這也是為什么會有內(nèi)容提供者的原因。

3.怎么使用內(nèi)容提供者?
         在理解了什么是內(nèi)容提供者,為什么會有內(nèi)容提供者之后,我想在大家腦海中的浮現(xiàn)的一個問題就是怎么使用內(nèi)容提供者,這也是今天我們要討論的重點內(nèi)容。在前面的博客我也說到學(xué)習(xí)這種東西的最好方法是看谷歌給出的官方文檔,那么好我們先來翻譯一段谷歌給出的介紹(注:這是本地的文檔,我采用的是脫機(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ù)通過單一的ContentResolver接口提供給應(yīng)用程序。當(dāng)你需要在多個應(yīng)用之間共享數(shù)據(jù)的時候就需要用到內(nèi)容提供者。例如,手機(jī)中的聯(lián)系人數(shù)據(jù)會被多個應(yīng)用所用到所以必須要用內(nèi)容提供者存儲起來。如果你不需要在多個應(yīng)用之間共享數(shù)據(jù),你可以使用一個數(shù)據(jù)庫,直接通過SQLite數(shù)據(jù)庫。 當(dāng)通過content resolver發(fā)送一個請求時,系統(tǒng)會檢查給定的URI并把請求傳給有注冊授權(quán)的Contentprovider。 UriMatcher類有助于解析uri。

需要實現(xiàn)的主要方法是:
public boolean onCreate() 在創(chuàng)建ContentProvider時調(diào)用
public Cursor query(Uri, String[], String, String[], String) 用于查詢指定Uri的ContentProvider,返回一個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類型

數(shù)據(jù)訪問的方法(如:insert(Uri, ContentValues) and update(Uri, ContentValues, String, String[]))可能被多個線程同時調(diào)用,此時必須是線程安全的。其他方法(如: onCreate())只能被應(yīng)用的主線程調(diào)用,它應(yīng)當(dāng)避免冗長的操作。ContentResolver(內(nèi)容解析者)請求被自動轉(zhuǎn)發(fā)到合適的內(nèi)容提供者實例,所以子類不需要擔(dān)心跨進(jìn)程調(diào)用的細(xì)節(jié)。

唉,每次最頭疼的就是看全英文的文檔,發(fā)現(xiàn)自己的英語水平太差,最近也在空閑時間學(xué)習(xí)學(xué)習(xí)英語,但是對于英語從來就沒感興趣過,希望自己可以堅持一段時間吧,其實在開發(fā)過程中遇到那些比較難解決的問題,在國外的有名的網(wǎng)站中基本都是可以查找到的,但是對于我這樣一個英語水平差的人來說,說多了其實都是眼淚。。。,我先哭一會。。。
關(guān)于怎樣使用ContentProvider后面有實例幫助大家理解。

4.Uri詳解
       在上面的翻譯中如果你認(rèn)真看的話你會發(fā)現(xiàn)在谷歌的官方文檔中提到了ContentResolver(內(nèi)容解析者),外界可以通過ContentResolver接口來訪問ContentProvider(內(nèi)容提供者)中的數(shù)據(jù)。但是在詳細(xì)了解ContentResolver之前有一項工作是必須要做的,那就是先理解Uri,在谷歌文檔中也有介紹,接下來我們就來詳細(xì)的學(xué)習(xí)下Uri這個類
Uri 通用資源標(biāo)志符(Universal Resource Identifier)Uri代表要操作的數(shù)據(jù),Android中可用的每種資源 - 圖像、視頻片段等都可以用Uri來表示。Uri的結(jié)構(gòu)由以下幾個部分組成
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ì)的劃分形式

看到這里肯定有人糊里糊涂的,接著我們就來舉一個例子來幫助大家詳細(xì)的理解Uri這個類的結(jié)構(gòu)
假如有這么一個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]來將這個Uri各個部分提取出來
scheme:根據(jù)標(biāo)準(zhǔn)格式可以看出這里的scheme就是Uri前面//前面的部分這里也就是http:。
fragment:dmk這個也是比較容易找到的,在#后面
query:id=15&name=du#dmk。從標(biāo)準(zhǔn)格式可以看到在"#"之前"?"之后的部分是query,在這里當(dāng)然就是id=15&name=du#dmk了。
authority:從格式二中可以看到authority是在//后的部分,它的終點就是在path之前所以這里的authority就是www.baidu.com:8080
path:path就是?之前,主機(jī)之后的部分那就是yourpath/fileName.html
host和port:因為主機(jī)可以分為host和port所以這里的host和port分別為:www.baidu.com和8080
這里要提醒大家注意的是:在Uri中并不是上述所有的字段都必須有的除了scheme、authority是必須要有的,其它的幾個path、query、fragment,它們每一個可以選擇性的要或不要,但順序不能變,比方說在上述Uri中沒有path那它的格式就為:http://www.baidu.com:8080/?id=15&name=du#dmk。
在理解了Uri的格式之后,有的人可能會說Uri的各個字段能否用代碼獲?。看鸢甘强隙ǖ?/span>
這里我們同樣以http://www.baidu.com:8080/yourpath/fileName.html?id=15&name=du#dmk為例
  • getScheme() :獲取Uri中的scheme字符串部分,在這里是http
  • getSchemeSpecificPart():獲取Uri中的scheme-specific-part:部分,這里是:http://www.baidu.com:8080/yourpath/fileName.html?
  • getFragment():獲取Uri中的fragment部分,即dmk
  • getAuthority():獲取Uri中Authority部分,即www.baidu.com:8080
  • getPath():獲取Uri中path部分,即/yourpath/fileName.html
  • getQuery():獲取Uri中的query部分,即id=15&name=du
  • getHost():獲取Authority中的Host字符串,即www.baidu.com
  • getPost():獲取Authority中的Port字符串,即8080
到這里關(guān)于Uri的介紹就完了(這里的關(guān)于Uri的介紹的內(nèi)容主要來自:Uri詳解之——Uri結(jié)構(gòu)與代碼提取 和 Java魔法堂:URI、URL(含URL Protocol Handler)

5.ContentResolver講解
       在了解了Uri之后就可以來學(xué)習(xí)學(xué)習(xí)ContentResolver了,前面我們說到ContentProvider共享數(shù)據(jù)是通過定義一個對外開放的統(tǒng)一的接口來實現(xiàn)的。然而,應(yīng)用程序并不直接調(diào)用這些方法,而是使用一個 ContentResolver 對象,調(diào)用它的方法作為替代。ContentResolver可以與任意內(nèi)容提供者進(jìn)行會話,與其合作來對所有相關(guān)交互通訊進(jìn)行管理。當(dāng)外部應(yīng)用需要對ContentProvider中的數(shù)據(jù)進(jìn)行添加、刪除、修改和查詢操作時,可以使用ContentResolver類來完成,要獲取ContentResolver對象,可以使用Context提供的getContentResolver()方法。ContentResolver cr = getContentResolver();在上面我們提到ContentProvider可以向其他應(yīng)用程序提供數(shù)據(jù),與之對應(yīng)的ContentResolver則負(fù)責(zé)獲取ContentProvider提供的數(shù)據(jù),修改、添加、刪除更新數(shù)據(jù)等;

ContentResolver 類也提供了與ContentProvider類相對應(yīng)的四個方法:
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ù)。

這些方法的第一個參數(shù)為Uri,代表要操作的是哪個ContentProvider和對其中的什么數(shù)據(jù)進(jìn)行操作,假設(shè)給定的是 Uri.parse(“content://com.qstingda.provider.personprovider/contact/15”),那么將會對主機(jī)名為com.qstingda.provider.personprovider的ContentProvider進(jìn)行操作,path為contact/15的數(shù)據(jù),看到這如果你之前沒有接觸過ContentProvider肯定一頭霧水,沒有關(guān)系,這很正常,等我們把理論知識講完后會有實例,相信你看過實例后就會很明白了。

6.UriMatch
      UriMatcher 類主要用于匹配Uri.這里的匹配是發(fā)生在ContentProvider中的,假如我們向ContentProvider中插入一條數(shù)據(jù),不可能為所欲為的想怎么干就怎么干,在ContentProvider肯定要做一個判斷,只有在符合條件下才會去執(zhí)行你想要執(zhí)行的操作,這里的判斷就是用UriMatch進(jìn)行匹配,假如是系統(tǒng)的ContentProvider如聯(lián)系人、圖庫、視頻庫等,這些系統(tǒng)都提供了Uri我們可以根據(jù)系統(tǒng)提供的Uri來操作相應(yīng)的數(shù)據(jù)。其實UriMatch的用法非常簡單,查閱谷歌官方文檔你會發(fā)現(xiàn)有這么幾個方法
publicUriMatcher(int code) 它的作用就是創(chuàng)建一個UriMatch對象
public voidaddURI(String authority,String path, int code)

它的作用是在ContentProvider添加一個用于匹配的Uri,當(dāng)匹配成功時返回code。Uri可以是精確的字符串,Uri中帶有*表示可匹配任意text,#表示只能匹配數(shù)字。

public int match(Uri uri) 這里的Uri就是傳過來的要進(jìn)行驗證,匹配的Uri假如傳過來的是:content://com.example.test/student/#,則content://com.example.test/student/10可以匹配成功,這里的10可以使任意的數(shù)字。


7.ContentObserver用法
         ContentObserver——內(nèi)容觀察者,從其名字我們可以看出它的作用就是觀察,觀察什么?觀察指定的Uri引起的數(shù)據(jù)庫的變化,然后通知主線程,根據(jù)需求做我們想要做的處理。這樣說大家可能理解的不是特別透徹,這樣跟大家說它可以實現(xiàn)類似于Adapter的notifyDataSetChanged()這個方法的作用,比方說當(dāng)觀察到ContentProvider的數(shù)據(jù)變化時會自動調(diào)用谷歌工程師給我們提供的好的方法,可以在此方法中通知主線程數(shù)據(jù)改變等等。那么問題來了,應(yīng)該怎樣實現(xiàn)這樣的功能呢?首先要做的就是注冊這個觀察者,這里的注冊是在需要監(jiān)測ContentProvider的應(yīng)用中進(jìn)行注冊并不是在ContentProvider中而在ContentProvider中要做的就是當(dāng)數(shù)據(jù)變化時進(jìn)行通知,這里的通知的方法谷歌已經(jīng)幫我們寫好,直接調(diào)用就行了,查看谷歌文檔你會發(fā)現(xiàn)在ContentResolver中有這樣的介紹:

public final void registerContentObserver (Uri uri, boolean notifyForDescendents, ContentObserver observer)

注冊一個觀察者實例,當(dāng)指定的Uri發(fā)生改變時,這個實例會回調(diào)實例對象做相應(yīng)處理。

參數(shù):uri:需要觀察的Uri

          notifyForDescendents:如果為true表示以這個Uri為開頭的所有Uri都會被匹配到

    如果為false表示精確匹配,即只會匹配這個給定的Uri。

  舉個例子,假如有這么幾個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時則以這個Uri開頭的Uri的數(shù)據(jù)變化時都會被捕捉到,在這里也就是①②③④的Uri的數(shù)據(jù)的變化都能被捕捉到,當(dāng)notifyForDescendents為false時則只有①中Uri變化時才能被捕捉到。

       看到registerContentObserver 這個方法,根據(jù)語言基礎(chǔ)我想大家能夠想到ContentResolver中的另一個方法

public final voidunregisterContentObserver(ContentObserverobserver)它的作用就是取消對注冊的那個Uri的觀察,這里傳進(jìn)去的就是在registerContentObserver中傳遞進(jìn)去的ContentObserver對象。到這關(guān)于注冊和解除注冊的ContentObserver可能大家都比較清楚了,那么問題來了,怎么去寫一個ContentObserver呢?其實它的實現(xiàn)很簡單,直接創(chuàng)建一個類繼承ContentObserver需要注意的是這里必須要實現(xiàn)它的構(gòu)造方法

public ContentObserver(Handlerhandler)

這里傳進(jìn)去的是一個Handler對象,這個Handler對象的作用一般要依賴于ContentObserver的另一個方法即

public void onChange(boolean selfChange)

這個方法的作用就是當(dāng)指定的Uri的數(shù)據(jù)發(fā)生變化時會回調(diào)該方法,此時可以借助構(gòu)造方法中的Handler對象將這個變化的消息發(fā)送給主線程,當(dāng)主線程接收到這個消息之后就可以按照我們的需求來完成相應(yīng)的操作,比如上面提到的類似于Adapter的notifyDataSetChanged()的作用,下面的案例也是完成了這個功能,準(zhǔn)備工作完成之后來看一個案例,相信這個案例會讓你對以上知識了解的更加深入。


8.案例(自定義ContentProvider)

    在真正的開發(fā)中我們很少去自定義一個ContentProvider因為ContentProvider是為了更好的去共享數(shù)據(jù),我們在開發(fā)中很少會遇到這種情況,而遇到更多的則是訪問系統(tǒng)的ContentProvider,系統(tǒng)的ContentProvider谷歌工程師已經(jīng)幫我們寫好了,我們直接使用就可以了,這里為了讓大家能夠理解ContentProvider更加徹底,我們自定義一個ContentProvider然后在其它應(yīng)用中來訪問自定義的ContentProvider的數(shù)據(jù)這個案例的運行效果如下:


    這里的插入數(shù)據(jù),是在一個項目中向另一個項目中的ContentProvider中插入一條數(shù)據(jù),其他的操作也是,接下來就來看看怎么實現(xiàn)上述的效果。
    在上面我們提到在自定義ContentProvider時需要繼承ContentProvider并實現(xiàn)3中所述的那幾個方法(系統(tǒng)會自動幫你將要復(fù)寫的方法羅列出來),那么我們自定義的PeopleContentProvider的代碼如下
  1. package com.example.contentproviderpractice;
  2. import android.content.ContentProvider;
  3. import android.content.ContentUris;
  4. import android.content.ContentValues;
  5. import android.content.UriMatcher;
  6. import android.database.Cursor;
  7. import android.database.sqlite.SQLiteDatabase;
  8. import android.net.Uri;
  9. public class PeopleContentProvider extends ContentProvider {
  10. //這里的AUTHORITY就是我們在AndroidManifest.xml中配置的authorities,這里的authorities可以隨便寫
  11. private static final String AUTHORITY = "com.example.studentProvider";
  12. //匹配成功后的匹配碼
  13. private static final int MATCH_ALL_CODE = 100;
  14. private static final int MATCH_ONE_CODE = 101;
  15. private static UriMatcher uriMatcher;
  16. private SQLiteDatabase db;
  17. private DBOpenHelper openHelper;
  18. private Cursor cursor = null;
  19. //數(shù)據(jù)改變后指定通知的Uri
  20. private static final Uri NOTIFY_URI = Uri.parse("content://" + AUTHORITY + "/student");
  21. //在靜態(tài)代碼塊中添加要匹配的 Uri
  22. static {
  23. //匹配不成功返回NO_MATCH(-1)
  24. uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  25. /**
  26. * uriMatcher.addURI(authority, path, code); 其中
  27. * authority:主機(jī)名(用于唯一標(biāo)示一個ContentProvider,這個需要和清單文件中的authorities屬性相同)
  28. * path:路徑路徑(可以用來表示我們要操作的數(shù)據(jù),路徑的構(gòu)建應(yīng)根據(jù)業(yè)務(wù)而定)
  29. * code:返回值(用于匹配uri的時候,作為匹配成功的返回值)
  30. */
  31. uriMatcher.addURI(AUTHORITY, "student", MATCH_ALL_CODE);// 匹配記錄集合
  32. uriMatcher.addURI(AUTHORITY, "student/#", MATCH_ONE_CODE);// 匹配單條記錄
  33. }
  34. @Override
  35. public boolean onCreate() {
  36. openHelper = new DBOpenHelper(getContext());
  37. db = openHelper.getWritableDatabase();
  38. return false;
  39. }
  40. @Override
  41. public int delete(Uri uri, String selection, String[] selectionArgs) {
  42. switch (uriMatcher.match(uri)) {
  43. /**
  44. * 這里如果匹配是uriMatcher.addURI(AUTHORITY, "student",
  45. * MATCH_SUCCESS_CODE);中的Uri,則我們可以在這里對這個ContentProvider中的數(shù)據(jù)庫
  46. * 進(jìn)行刪除等操作。這里如果匹配成功,我們將刪除所有的數(shù)據(jù)
  47. */
  48. case MATCH_ALL_CODE:
  49. int count=db.delete("personData", null, null);
  50. if(count>0){
  51. notifyDataChanged();
  52. return count;
  53. }
  54. break;
  55. /**
  56. * 這里如果匹配是uriMatcher.addURI(AUTHORITY,
  57. * "student/#",MATCH_ONE_CODE);中的Uri,則說明我們要操作單條記錄
  58. */
  59. case MATCH_ONE_CODE:
  60. // 這里可以做刪除單條數(shù)據(jù)的操作。
  61. break;
  62. default:
  63. throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
  64. }
  65. return 0;
  66. }
  67. @Override
  68. public String getType(Uri uri) {
  69. return null;
  70. }
  71. /**
  72. * 插入 使用UriMatch的實例中的match方法對傳過來的 Uri進(jìn)行匹配。 這里通過ContentResolver傳過來一個Uri,
  73. * 用這個傳過來的Uri跟在ContentProvider中靜態(tài)代碼塊中uriMatcher.addURI加入的Uri進(jìn)行匹配
  74. * 根據(jù)匹配的是否成功會返回相應(yīng)的值,在上述靜態(tài)代碼塊中調(diào)用uriMatcher.addURI(AUTHORITY,
  75. * "student",MATCH_CODE)這里的MATCH_CODE
  76. * 就是匹配成功的返回值,也就是說假如返回了MATCH_CODE就表示這個Uri匹配成功了
  77. * ,我們就可以按照我們的需求就行操作了,這里uriMatcher.addURI(AUTHORITY,
  78. * "person/data",MATCH_CODE)加入的Uri為:
  79. * content://com.example.studentProvider/student
  80. * ,如果傳過來的Uri跟這個Uri能夠匹配成功,就會按照我們設(shè)定的步驟去執(zhí)行相應(yīng)的操作
  81. */
  82. @Override
  83. public Uri insert(Uri uri, ContentValues values) {
  84. int match=uriMatcher.match(uri);
  85. if(match!=MATCH_ALL_CODE){
  86. throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
  87. }
  88. long rawId = db.insert("personData", null, values);
  89. Uri insertUri = ContentUris.withAppendedId(uri, rawId);
  90. if(rawId>0){
  91. notifyDataChanged();
  92. return insertUri;
  93. }
  94. return null;
  95. }
  96. /**
  97. * 查詢 如果uri為
  98. * content://com.example.studentProvider/student則能匹配成功,然后我們可以按照需求執(zhí)行匹配成功的操作
  99. */
  100. @Override
  101. public Cursor query(Uri uri, String[] projection, String selection,
  102. String[] selectionArgs, String sortOrder) {
  103. switch (uriMatcher.match(uri)) {
  104. /**
  105. * 如果匹配成功,就根據(jù)條件查詢數(shù)據(jù)并將查詢出的cursor返回
  106. */
  107. case MATCH_ALL_CODE:
  108. cursor = db.query("personData", null, null, null, null, null, null);
  109. break;
  110. case MATCH_ONE_CODE:
  111. // 根據(jù)條件查詢一條數(shù)據(jù)。。。。
  112. break;
  113. default:
  114. throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
  115. }
  116. return cursor;
  117. }
  118. @Override
  119. public int update(Uri uri, ContentValues values, String selection,
  120. String[] selectionArgs) {
  121. switch (uriMatcher.match(uri)) {
  122. case MATCH_ONE_CODE:
  123. long age = ContentUris.parseId(uri);
  124. selection = "age = ?";
  125. selectionArgs = new String[] { String.valueOf(age) };
  126. int count = db.update("personData", values, selection,selectionArgs);
  127. if(count>0){
  128. notifyDataChanged();
  129. }
  130. break;
  131. case MATCH_ALL_CODE:
  132. // 如果有需求的話,可以對整個表進(jìn)行操作
  133. break;
  134. default:
  135. throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
  136. }
  137. return 0;
  138. }
  139. //通知指定URI數(shù)據(jù)已改變
  140. private void notifyDataChanged() {
  141. getContext().getContentResolver().notifyChange(NOTIFY_URI, null);
  142. }
  143. }
可以看到在onCreate()方法中創(chuàng)建了一個數(shù)據(jù)庫,關(guān)于數(shù)據(jù)庫的操作大家可以看此博客http://blog.csdn.net/dmk877/article/details/44876805。這里就不多做介紹了。注意這個案例牽扯到兩個項目,一個是包含我們自定義的ContentProvider,另一個項目是訪問這個包含ContentProvider項目中的數(shù)據(jù)。
寫好PeopleContentProvider之后千萬不要忘了在清單文件中注冊
  1. <provider
  2. android:name="com.example.contentproviderpractice.PeopleContentProvider"
  3. android:authorities="com.example.student"
  4. android:exported="true" >
  5. </provider>
這里的authorities就是它是唯一標(biāo)識內(nèi)容提供者的,為內(nèi)容提供者指定一個唯一的標(biāo)識,這樣別的應(yīng)用才可以唯一獲取此provider,exported的值為[flase|true]當(dāng)為true時:當(dāng)前提供者可以被其它應(yīng)用使用。任何應(yīng)用可以使用Provider通過URI 來獲得它,也可以通過相應(yīng)的權(quán)限來使用Provider。當(dāng)為false時:當(dāng)前提供者不能被其它應(yīng)用使用,默認(rèn)為true。注冊好之后運行到手機(jī)上,此時其它的應(yīng)用就可以通過ContentResolver來訪問這個PeopleContentProvider了,具體怎么操作呢?我們再新建一個項目在MainActivity的代碼如下:
  1. package com.example.otherapplication;
  2. import java.util.ArrayList;
  3. import com.example.otherapplication.adapter.MyAdapter;
  4. import com.example.otherapplication.bean.Student;
  5. import com.example.otherapplication.observer.PersonOberserver;
  6. import android.net.Uri;
  7. import android.os.Bundle;
  8. import android.os.Handler;
  9. import android.app.Activity;
  10. import android.content.ContentResolver;
  11. import android.content.ContentUris;
  12. import android.content.ContentValues;
  13. import android.database.Cursor;
  14. import android.view.View;
  15. import android.view.View.OnClickListener;
  16. import android.widget.Button;
  17. import android.widget.ListView;
  18. public class MainActivity extends Activity implements OnClickListener {
  19. private ContentResolver contentResolver;
  20. private ListView lvShowInfo;
  21. private MyAdapter adapter;
  22. private Button btnInit;
  23. private Button btnInsert;
  24. private Button btnDelete;
  25. private Button btnUpdate;
  26. private Button btnQuery;
  27. private Cursor cursor;
  28. private static final String AUTHORITY = "com.example.studentProvider";
  29. private static final Uri STUDENT_ALL_URI = Uri.parse("content://" + AUTHORITY + "/student");
  30. protected static final String TAG = "MainActivity";
  31. private Handler handler=new Handler(){
  32. public void handleMessage(android.os.Message msg) {
  33. //在此我們可以針對數(shù)據(jù)改變后做一些操作,比方說Adapter.notifyDataSetChanged()等,根據(jù)業(yè)務(wù)需求來定。。
  34. cursor = contentResolver.query(STUDENT_ALL_URI, null, null, null,null);
  35. adapter.changeCursor(cursor);
  36. };
  37. };
  38. @Override
  39. protected void onCreate(Bundle savedInstanceState) {
  40. super.onCreate(savedInstanceState);
  41. setContentView(R.layout.activity_main);
  42. lvShowInfo=(ListView) findViewById(R.id.lv_show_info);
  43. initData();
  44. }
  45. private void initData() {
  46. btnInit=(Button) findViewById(R.id.btn_init);
  47. btnInsert=(Button) findViewById(R.id.btn_insert);
  48. btnDelete=(Button) findViewById(R.id.btn_delete);
  49. btnUpdate=(Button) findViewById(R.id.btn_update);
  50. btnQuery=(Button) findViewById(R.id.btn_query);
  51. btnInit.setOnClickListener(this);
  52. btnInsert.setOnClickListener(this);
  53. btnDelete.setOnClickListener(this);
  54. btnUpdate.setOnClickListener(this);
  55. btnQuery.setOnClickListener(this);
  56. contentResolver = getContentResolver();
  57. //注冊內(nèi)容觀察者
  58. contentResolver.registerContentObserver(STUDENT_ALL_URI,true,new PersonOberserver(handler));
  59. adapter=new MyAdapter(MainActivity.this,cursor);
  60. lvShowInfo.setAdapter(adapter);
  61. }
  62. @Override
  63. public void onClick(View v) {
  64. switch (v.getId()) {
  65. //初始化
  66. case R.id.btn_init:
  67. ArrayList<Student> students = new ArrayList<Student>();
  68. Student student1 = new Student("蒼老師",25,"一個會教學(xué)的好老師");
  69. Student student2 = new Student("柳巖",26,"大方");
  70. Student student3 = new Student("楊冪",27,"漂亮");
  71. Student student4 = new Student("張馨予",28,"不知道怎么評價");
  72. Student student5 = new Student("范冰冰",29,"。。。");
  73. students.add(student1);
  74. students.add(student2);
  75. students.add(student3);
  76. students.add(student4);
  77. students.add(student5);
  78. for (Student Student : students) {
  79. ContentValues values = new ContentValues();
  80. values.put("name", Student.getName());
  81. values.put("age", Student.getAge());
  82. values.put("introduce", Student.getIntroduce());
  83. contentResolver.insert(STUDENT_ALL_URI, values);
  84. }
  85. break;
  86. //增
  87. case R.id.btn_insert:
  88. Student student = new Student("小明", 26, "帥氣男人");
  89. //實例化一個ContentValues對象
  90. ContentValues insertContentValues = new ContentValues();
  91. insertContentValues.put("name",student.getName());
  92. insertContentValues.put("age",student.getAge());
  93. insertContentValues.put("introduce",student.getIntroduce());
  94. //這里的uri和ContentValues對象經(jīng)過一系列處理之后會傳到ContentProvider中的insert方法中,
  95. //在我們自定義的ContentProvider中進(jìn)行匹配操作
  96. contentResolver.insert(STUDENT_ALL_URI,insertContentValues);
  97. break;
  98. //刪
  99. case R.id.btn_delete:
  100. //刪除所有條目
  101. contentResolver.delete(STUDENT_ALL_URI, null, null);
  102. //刪除_id為1的記錄
  103. Uri delUri = ContentUris.withAppendedId(STUDENT_ALL_URI,1);
  104. contentResolver.delete(delUri, null, null);
  105. break;
  106. //改
  107. case R.id.btn_update:
  108. ContentValues contentValues = new ContentValues();
  109. contentValues.put("introduce","性感");
  110. //更新數(shù)據(jù),將age=26的條目的introduce更新為"性感",原來age=26的introduce為"大方".
  111. //生成的Uri為:content://com.example.studentProvider/student/26
  112. Uri updateUri = ContentUris.withAppendedId(STUDENT_ALL_URI,26);
  113. contentResolver.update(updateUri,contentValues, null, null);
  114. break;
  115. //查
  116. case R.id.btn_query:
  117. //通過ContentResolver獲得一個調(diào)用ContentProvider對象
  118. Cursor cursor = contentResolver.query(STUDENT_ALL_URI, null, null, null,null);
  119. //CursorAdapter的用法,參考此博客:http://blog.csdn.net/dmk877/article/details/44983491
  120. adapter=new MyAdapter(MainActivity.this,cursor);
  121. lvShowInfo.setAdapter(adapter);
  122. cursor = contentResolver.query(STUDENT_ALL_URI, null, null, null,null);
  123. adapter.changeCursor(cursor);
  124. break;
  125. }
  126. }
  127. }
    可以看出若想操作我們想操作的ContentProvider,必須要知道內(nèi)容提供者的Uri,再正確得到Uri之后,就可以通過ContentResolver對象來操作ContentProvider中的數(shù)據(jù)了,假如你需要插入數(shù)據(jù)只需要調(diào)用contentResolver.insert(uri, contentValues);把正確的uri和ContentValues鍵值對傳過去就行了。執(zhí)行這句話系統(tǒng)就會根據(jù)我們提供的uri找到對應(yīng)的ContentProvider,因為我們的uri中包含了authority(主機(jī)等各種信息),得到對應(yīng)的ContentProvider后將調(diào)用ContentResolver的與之對應(yīng)的增刪改查方法,并將參數(shù)通過ContentResolver的增刪改查方法傳遞到ContentProvider中。在上面用到了CursorAdapter關(guān)于CursorAdapter的用法可以參考此博客http://blog.csdn.net/dmk877/article/details/44983491

PersonObserver的代碼如下
  1. package com.example.otherapplication.observer;
  2. import android.database.ContentObserver;
  3. import android.os.Handler;
  4. import android.os.Message;
  5. public class PersonOberserver extends ContentObserver {
  6. private Handler handler;
  7. public PersonOberserver(Handler handler) {
  8. super(handler);
  9. this.handler=handler;
  10. }
  11. @Override
  12. public void onChange(boolean selfChange) {
  13. super.onChange(selfChange);
  14. //向handler發(fā)送消息,更新查詢記錄
  15. Message msg = new Message();
  16. handler.sendMessage(msg);
  17. }
  18. }
可以看到,在構(gòu)造方法中接收了Handler然后當(dāng)監(jiān)聽到指定的Uri的數(shù)據(jù)變化時就會通過Handler消息機(jī)制發(fā)送一條消息,然后的操作就由我們自行完成了。

到這里我們來理一理整個操作的運行流程:首先有兩個項目,一個是有ContentProvider的,在這個ContentProvider中初始化了一個數(shù)據(jù)庫,我們的目的就是在另一個項目中來操作這個項目中ContentProvider中的數(shù)據(jù),例如插入一條數(shù)據(jù),查詢等。對于怎么在另一個項目中操作ContentProvider中的數(shù)據(jù),是通過ContentResolver(內(nèi)容解析者)對象來操作的,假如我們要進(jìn)行insert操作,那么需要調(diào)用ContentResolver的insert(uri, ContentValues);將Uri和ContentValues對象經(jīng)過一系列操作傳遞到ContentProvider的中,然后在ContentProvider會對這個Uri進(jìn)行匹配,如果匹配成功則按照我們的需求去執(zhí)行相應(yīng)的操作,如:插入數(shù)據(jù)、查詢數(shù)據(jù)等。如果想進(jìn)一步理解ContentProvider和ContentResolver之間的關(guān)系http://blog.csdn.net/u010961631/article/details/14227421(對這個過程從源碼進(jìn)行了解析,不建議初學(xué)者閱讀)。下面我們來畫一張圖再來說一下這個過程
從圖中可以看出在OtherApplication中注冊了ContentObserver之后,當(dāng)Application1中的數(shù)據(jù)庫發(fā)生了變化時,只需要在ContentProvider中調(diào)用ContentResolver的notifyChange(Uri,ContentObserver observer),由于在OtherApplication中注冊了ContentObserver(注冊時用的Uri和ContentProvider中發(fā)生變化的Uri一樣)因此在ContentObserver中會收到這個變化信息,它就可以將這個消息通過Handler發(fā)送給OtherApplication。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
ContentProvider實例詳解
ContentProvider
android-關(guān)于ContentProvider的使用
android四大組件--ContentProvider詳解
Content Provider
[Android]Android數(shù)據(jù)的四種存儲方式 - Ron Ngai - 博客園
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服