四大組件-內(nèi)容提供者ContentProvider

定義

內(nèi)容提供者,是Android四大組件之一

作用

進程之間進行數(shù)據(jù) 交互、共享 ,即跨進程通信

1.內(nèi)容提供者只是搬運工,真正的存儲、操作數(shù)據(jù)的數(shù)據(jù)源還是原來存儲數(shù)據(jù)的方式(數(shù)據(jù)庫、文件、xml或網(wǎng)絡(luò))
2.數(shù)據(jù)源可以為:數(shù)據(jù)庫、文件、XML或網(wǎng)絡(luò)等

原理

ContentProvider的底層原理 即為 Binder的機制

具體使用

ContentProvider的使用主要有以下內(nèi)容:

1.統(tǒng)一資源標識符(URI)
  • 定義:URI(Uniform Resource Identifier),即統(tǒng)一資源標識符
  • 作用:唯一標識ContentProvider及其中的數(shù)據(jù)

外界進程通過URI找到對應(yīng)的ContentProvider及其中的數(shù)據(jù),再進行數(shù)據(jù)操作

  • 具體使用
    URI分為系統(tǒng)預置和自定義,分別對應(yīng)系統(tǒng)內(nèi)置數(shù)據(jù)(通訊錄、日程表等)和自定義數(shù)據(jù)庫

自定義URI=content://com.wz.provider/User/1 , 其中

  • 主題Schema(content):ContentProvider的URI前綴(Android規(guī)定)
  • 授權(quán)信息Authority(com.wz.provider) :ContentProvider的唯一標識符
  • 表名Path(User):ContentProvider指向數(shù)據(jù)庫的某個表名
  • 記錄ID(1):表中的某個記錄(若無指定則返回全部記錄)
//設(shè)置URI
Uri uri=Uri.parse("content://com.wz.provider/User/1")
// 上述URI指向的資源是:名為 `com.wz.provider`的`ContentProvider` 中表名 為`User` 中的 `id`為1的數(shù)據(jù)
// 特別注意:URI模式存在匹配通配符* & #

// *:匹配任意長度的任何有效字符的字符串
// 以下的URI 表示 匹配provider的任何內(nèi)容
content://com.example.app.provider/* 

// #:匹配任意長度的數(shù)字字符的字符串
// 以下的URI 表示 匹配provider中的table表的所有行
content://com.example.app.provider/table/#
2.MIME數(shù)據(jù)類型
  • 作用:指定某個擴展名的文件用某種應(yīng)用程序來打開,例如指定.html文件采用text應(yīng)用程序打開

  • 具體使用:

    ContentProvider根據(jù)URI返回MIME類型
    ContentProvider.getType(uri);
    
    MIME類型組成

    每種MIME類型由兩部分組成:類型+子類型(MIME是一個字符串)

    text/html  
    text=類型,html=子類型
    
    MIME類型形式

    MIME類型有2種形式:單條記錄、多條記錄

    //形式1:單條記錄
    vnd.android.cursor.item/自定義
    //形式2:多條記錄
    vnd.android.cursor.dir/自定義
    
    //1. vnd:表示父類型和子類型具有非標準、特定的形式。
    //2. vnd:父類型已經(jīng)固定好(即不能更改),只能區(qū)別是單條還是多條
    //3. 子類型可自定義
    

    實例

    < -- 單條記錄 -- >
      //單個記錄的MIME類型
      vnd.android.cursor.item/vnd.yourcompanyname.contenttype 
      
      //若一個uri如下
      content://com.example.transportationprovider/trains/122   
      // 則ContentProvider會通過ContentProvider.geType(url)返回以下MIME類型
      vnd.android.cursor.item/vnd.example.rail
    
    
    < -- 多條記錄 -- >
      //多條記錄的MIME類型
      vnd.android.cursor.dir/vnd.yourcompanyname.contenttype
    
       // 若一個Uri如下
      content://com.example.transportationprovider/trains
       // 則ContentProvider會通過ContentProvider.geType(url)返回以下MIME類型
      vnd.android.cursor.dir/vnd.example.rail
    
3.ContentProvider類
組織數(shù)據(jù)的方式
  • ContentProvider主要以 表格的形式 組織數(shù)據(jù)(同時也支持文件數(shù)據(jù),表格用得比較多)
  • 每個表格中包含多張表,每張表包含行、列、分別對應(yīng)記錄、字段(行==記錄,列==字段)
主要方法
  • 進程間共享數(shù)據(jù)的本質(zhì)就是:添加、刪除、獲取、更新。所以ContentProvider的核心方法也主要是上述4個作用

    < -- 4個核心方法 -- >
      //外部進程向ContentProvider  中 添加 數(shù)據(jù)
      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)
    //注
      1.上述四個方法由外部進程回調(diào),并運行在ContentProvider進程的Binder線程池中(不是主線程)
      2.存在多線程并發(fā)訪問,需要實現(xiàn)線程同步(單個SQLite不需要,SQLite內(nèi)部已經(jīng)實現(xiàn)了線程同步)
    < -- 2個其他方法 -- >
      //ContentProvider創(chuàng)建后 或 打開系統(tǒng)后其他進程第一次訪問該ContentProvider時,由系統(tǒng)進行調(diào)用
      //注:運行在ContentProvider進程的主線程,故不能做耗時操作
      public boolean onCreate()
    
      //得到數(shù)據(jù)類型,即返回當前Uri所代表數(shù)據(jù)的MIME類型
      public Stirng getType(Uri uri)
    
  • Android為常見的數(shù)據(jù)(通訊錄、日程表)提供了內(nèi)置默認的ContentProvider,但也可以根據(jù)需求自定義ContentProvider(重寫上述6個方法)

  • ContentProvider類不會直接與外部進程進行交互,而是通過ContentResolver類

ContentResolver類
作用:
  • 統(tǒng)一管理不同ContentProvider間的操作

    1.通過URI即可操作不同的ContentProvider中的數(shù)據(jù)
    2.外部進程通過ContentResolver類從而與ContentProvider類進行交互

ContentResolver存在的原因:
  • 一般來說,一款應(yīng)用要使用多個ContentProvider,若需要了解每個ContentProvider的不同實現(xiàn)從而完成數(shù)據(jù)的交互,操作成本高、難度大。所以在ContentProvider的基礎(chǔ)上多加了一個ContentResolver類對所有ContentProvider進行統(tǒng)一管理。
使用:
  • ContentResolver類提供了與ContentProvider相同名字和作用的4個方法

    //外部進程向 ContentProvider 中添加數(shù)據(jù)
    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)  
    
    // 外部應(yīng)用 獲取 ContentProvider 中的數(shù)據(jù)
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
    
  • 實例說明

    // 使用ContentResolver前,需要先獲取ContentResolver
    // 可通過在所有繼承Context的類中 通過調(diào)用getContentResolver()來獲得ContentResolver
    ContentResolver resolver =  getContentResolver();
    // 設(shè)置ContentProvider的URI
    Uri uri = Uri.parse("content://cn.scu.myprovider/user"); 
    // 根據(jù)URI 操作 ContentProvider中的數(shù)據(jù)
    // 此處是獲取ContentProvider中 user表的所有記錄 
    Cursor cursor = resolver.query(uri, null, null, null, "userid desc"); 
    
4.輔助工具類
ContentUris類
  • 作用:操作URI
  • 具體使用:
    兩個核心方法:
    • withAppendedId() == 向URI追加一個id

    • parseId() == 從URI中獲取id

      // withAppendedId()作用:向URI追加一個id
      Uri uri = Uri.parse("content://cn.scu.myprovider/user") 
      Uri resultUri = ContentUris.withAppendedId(uri, 7);  
      // 最終生成后的Uri為:content://cn.scu.myprovider/user/7
      
      // parseId()作用:從URL中獲取ID
      Uri uri = Uri.parse("content://cn.scu.myprovider/user/7") 
      long personid = ContentUris.parseId(uri); 
      //獲取的結(jié)果為:7
      
UriMatcher類
  • 作用:
    1.在ContentProvider中注冊URI
    2.根據(jù)URI匹配ContentProvider中對應(yīng)的數(shù)據(jù)表

  • 使用
    步驟1:初始化UriMatcher對象
    步驟2:在ContentProvider 中注冊URI( addURI() )
    步驟3:根據(jù)URI 匹配 URI_CODE,從而匹配ContentProvider中相應(yīng)的資源( match() )

    //步驟1:初始化UriMatcher對象
      UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); 
       //常量UriMatcher.NO_MATCH  = 不匹配任何路徑的返回碼
      // 即初始化時不匹配任何東西
    
    // 步驟2:在ContentProvider 中注冊URI(addURI())
      int URI_CODE_a = 1;
      int URI_CODE_b = 2;
      matcher.addURI("cn.scu.myprovider", "user1", URI_CODE_a); 
      matcher.addURI("cn.scu.myprovider", "user2", URI_CODE_b); 
      // 若URI資源路徑 = content://cn.scu.myprovider/user1 ,則返回注冊碼URI_CODE_a
      // 若URI資源路徑 = content://cn.scu.myprovider/user2 ,則返回注冊碼URI_CODE_b
    
    // 步驟3:根據(jù)URI 匹配 URI_CODE,從而匹配ContentProvider中相應(yīng)的資源(match())
      @Override   
       public String getType(Uri uri) {   
        Uri uri = Uri.parse(" content://cn.scu.myprovider/user1");   
    
        switch(matcher.match(uri)){   
         // 根據(jù)URI匹配的返回碼是URI_CODE_a
         // 即matcher.match(uri) == URI_CODE_a
          case URI_CODE_a:   
          return tableNameUser1;   
        // 如果根據(jù)URI匹配的返回碼是URI_CODE_a,則返回ContentProvider中的名為tableNameUser1的表
          case URI_CODE_b:   
          return tableNameUser2;
      // 如果根據(jù)URI匹配的返回碼是URI_CODE_b,則返回ContentProvider中的名為tableNameUser2的表
      }   
    }
    
ContentObserver類
  • 定義:內(nèi)容觀察者

  • 作用:觀察uri引起ContentProvider中的數(shù)據(jù)變化(當ContentProvider中的數(shù)據(jù)發(fā)生增、刪、改時就會觸發(fā)ContentObserver類)并通知外界(即 訪問 該數(shù)據(jù)的訪問者)

  • 使用:

    // 步驟1:注冊內(nèi)容觀察者ContentObserver
         // 通過ContentResolver類進行注冊,并指定需要觀察的URI
        getContentResolver().registerContentObserver(uri);
      
    
    // 步驟2:當該URI的ContentProvider數(shù)據(jù)發(fā)生變化時,通知外界(即訪問該ContentProvider數(shù)據(jù)的訪問者)
        public class UserContentProvider extends ContentProvider { 
          public Uri insert(Uri uri, ContentValues values) {
          db.insert("user", "userid", values);
          // 通知訪問者
          getContext().getContentResolver().notifyChange(uri, null);
            }
          }
    
    // 步驟3:解除觀察者
        // 同樣需要通過ContentResolver類進行解除
        getContentResolver().unregisterContentObserver(uri);
    
5.實例使用

ContentProvider不僅可以用于進程之間的通信,也可以用于進程內(nèi)的通信

  • 進程內(nèi)通信
    步驟:

    1.創(chuàng)建數(shù)據(jù)庫類
    2.自定義ContentProvider類(創(chuàng)建提供者)
    3.注冊創(chuàng)建的ContentProvider類(注冊提供者,在清單配置文件注冊)
    4.訪問ContentProvider類的數(shù)據(jù)

6.感謝

文章出處:簡書大神 Carson_Ho
博客地址:http://www.itdecent.cn/p/ea8bc4aaf057

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容