ContentProvider主要用于在不同的应用程序之间实现数据共享,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性,目前内容提供其实android实现跨进程共享数据的标准方式。

ContentProvider的用法一般有两种,一种是使用ContentResolver来读取和操作应用程序中ContentProvider共享的数据,另一种就是创建自己的ContentProvider子类给我们的程序提供外部访问的接口。

其中ContentProvider负责

  • 组织应用程序的数据;
  • 向其他应用程序提供数据;

ContentResolver则负责

  • 获取ContentProvider提供的数据;
  • 修改/添加/删除更新数据等;

 

一、ContentResolver访问应用中ContentProvider的共享数据:

     (1)获取ContentResolver对象:

     可以使用Context中的getContentResolver()方法来获取ContentResolver对象。

     (2)使用ContentResolver对象提供一系列方法对数据进行CRUD等操作:

            主要使用的方法就是关于数据的增删改查方法:

            Uri insert(Uri url, ContentValues values)

            int delete(Uri url, String where, String[] selectionArgs) 

            int update(Uri uri, ContentValues values, String where, String[] selectionArgs) 

       Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 

 

            不同于SQLiteDatabase,ContentResolver中的增删改查方法都是不接收表名参数的,而是使用一个Uri参数代替,这个参数被称为内容URI。

 

            内容URI给ContentProvider中的数据建立提供了唯一标示。

 

            ContentResolver中的增删改查方法都接收内容URI作为参数,使用内容URI可以清楚的表名当前的ContentResolver要访问的是哪一个应用了程序中的哪一个数据表。

 

           内容URI由两部分组成:权限(用来对不同的应用程序作区分,一般为了避免冲突,都会采用应用包名的方式来进行命名)和路径(为了对一应用程序中的不同表来作区分)

           eg:com.example.app为应用包名,table为应用中表名

                  权限可命名为:com.example.app.provider;路径可命名为:/table

 

           完整的内容URI字符串还需要在权限和路径组成的字符串头部加上协议声明,那么完整的URI写法为:

           content://com.example.app.provider/table/id [还可以在末尾加上一个id值,表示为table表中id值为指定值的数据]

 

           得到URI字符串后还需要将其转化为URI对象才能被ContentResolver中的方法使用:

           Uri uri=Uri.parse("content://com.example.app.provider/table");

 

           CotentResolver中对数据的操作除了操作的数据源的写法与SQLite中不一致外,其他参数的使用均与SQLite中的写法大体相同,故不再一一赘述。

 

二、使用ContentProvider向外提供数据访问的接口

      1、新建ContentProvider的实现类重写其中的六个方法。

      2、CpntentProvider中使用的内容URI的格式主要有两种,以路径结尾表示查询表中全部数据,以id结尾表示希望访问表中指定id值的数据。

 

           可以使用通配符来分别匹配这两种格式的内容URI,规则如下:

            1、*表示匹配任意长度的任意字符

                  表示匹配任意表的内容URI格式可以写成:content://com.example.app.provider/*

            2、#表示匹配任意长度的字符

                 表示匹配table表中任意一行数据的内容URI格式可以写成:content://com.example.app.provider/table/#

 

          使用UriMatcher这个类就可以实现内容URI的匹配功能

          UriMatcher中提供了addURI(String authority, String path, int code)方法可以将权限、路径和一个自定的代码传进去,这样当调用UriMatcher的match(Uri Uri)方法时就可以将Uri与一个自定义的代码对应起来,利用这个代码我们就可以判断出外部应用期望访问的是哪一张表中的数据了,之后就可以对数据表中的数据进行操作并返回操作结构给外部应用请求的ContentResolver了。

static{
            urimatcher=new UriMatcher(UriMatcher.NO_MATCH);
            urimatcher.addURI("com.example.app.provider", "table1", TABLE1_DIR);
            urimatcher.addURI("com.example.app.provider", "table1/#", TABLE1_DIR);
        }


@Override
        public Cursor query(Uri uri, String[] projection, String selection,
                String[] selectionArgs, String sortOrder) {
            // TODO Auto-generated method stub
            switch (urimatcher.match(uri)) {
            case TABLE1_DIR:
                //查询table1中所有数据
                break;

            case TABLE1_ITEM:
                //查询table1中单条数据
                break;
            }
            return null;
        }

 

3.ContentProvider中的getType(Uri Uri)方法,用于获取Uri对象对应的MIME类型。

  一个内容URI所对应的MIME类型字符串主要有三部分组成,Android对这三部分做了如下规定:

   (1)必须以vnd开头;

   (2)如果内容URI以路径结尾,则后接android.cursor.dir/,如果内容URI以id结尾则后接android.cursor.item/;

   (3)最后接上vnd.<authority>.<path>;

eg:content://com.example.app.provider/table这样的内容URI,对应MIME类型字符串为:

     vnd.android.cursor.dir/vnd.com.example.app.provider.table

 

     那么ContentProvider中的getType()写法如下:

    

@Override
        public String getType(Uri uri) {
            // TODO Auto-generated method stub
            switch (urimatcher.match(uri)) {
            case TABLE1_DIR:
                return "vnd.android.cursor.dir/vnd.com.example.app.provider.table1";
                break;

            case TABLE1_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.app.provider.table1";
                break;
            }
            
        }

 4、在AndroidManifest.xml文件中加入<provider>标签

        <provider 
            android:name="com.example.app.myProvider"
            android:authorities="com.example.app.provider"
            android:exported="true">
        </provider>

 

 name:ContentProvider子类的完整包名

authorities:指定此ContentProvider的权限名

exported:指定此ContentProvider是可以被其他程序引用的

 

 

 

 

 完整的Contentprovider写法:

 
class myProvider extends ContentProvider{
        //访问table1中的全部数据
        public static final int TABLE1_DIR=0;
        //访问table1中的单条数据
        public static final int TABLE1_ITEM=1;
        private static UriMatcher urimatcher;
static{ urimatcher=new UriMatcher(UriMatcher.NO_MATCH); urimatcher.addURI("com.example.app.provider", "table1", TABLE1_DIR); urimatcher.addURI("com.example.app.provider", "table1/#", TABLE1_DIR); }
/** *初始化ContentProvider时使用 *通常会在这里完成对数据库的创建和升级等操作 *只有当存在ContentResolver尝试访问我们程序中的数据时,ContentProvider才会被初始化 **/

@Override public boolean onCreate() { // TODO Auto-generated method stub return false; }
/** * 提供的数据查询接口 */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // TODO Auto-generated method stub switch (urimatcher.match(uri)) { case TABLE1_DIR: //查询table1中所有数据 break; case TABLE1_ITEM: //查询table1中单条数据 break; } return null; }
/** * 提供的数据插入接口 */ @Override public Uri insert(Uri uri, ContentValues values) { // TODO Auto-generated method stub return null; }
/** * 提供的数据删除接口 */ @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // TODO Auto-generated method stub return 0; }
/** * 提供的更新接口 */ @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO Auto-generated method stub return 0; }
/** * 根据ContentResolver传入的URI来返回相应的MIME类型 */ @Override public String getType(Uri uri) { // TODO Auto-generated method stub switch (urimatcher.match(uri)) { case TABLE1_DIR: return "vnd.android.cursor.dir/vnd.com.example.app.provider.table1"; break; case TABLE1_ITEM: return "vnd.android.cursor.item/vnd.com.example.app.provider.table1"; break; } } }