【Android】四大组件之ContentProvider

Android四大组件之ContentProvider

Date:2018/07/10

ContentProvider是Android四大组件之一,主要用于在不同应用间实现数据共享的功能。是Android实现跨程序共享数据的标准方式。

ContentProvider的基本使用

ContentProvider一般有两种用法,一种是用现有的ContentProvider来读取与操作相应程序的数据。另一种是创建自己的ContentProvider给程序的数据提供外部访问的接口。如果一个程序通过ContentProvider对它的数据提供了外部访问接口,则任何其他程序都可以对此部分数据进行访问。

读取数据:ContentResolver的使用

要访问ContentProvider中共享的内容,一般都会用到ContentResolver类。可以通过Context的getContentResolver()方法来获取该类的实例。其中提供了一系列方法来对数据进行增删查改。

与SQLite不同的是,ContentProvider的增删查改并不是接收表名参数,而是用内容URI。

内容URI

内容URI主要由两部分组成,authority与path。比如一个包名为com.android.test的app,它的authority就可以命名为com.android.test.provider。path是对一个应用程序不同的表做区分的,通常添加到authority的后面。如某个程序数据库中有两个表table1和table2,这时path就可以是/table1或者/table2。authority与path组合后,在头部加上协议声明后,就是一个标准的内容URI了。如:

content://com.android.test.provider/table1

content://com.android.test.provider/table2

得到内容URI字符串后,通过Uri类的parse方法即可将其解析为Uri对象了。

Uri uri = Uri.parse("content://com.android.test.provider/table1");

如果要访问的是table表中id为1的数据,可以通过uri后加上/id来实现。如:

Uri uri = Uri.parse("content://com.android.test.provider/table1/1");

Uri中还有两种通配符:

  • *****:表示匹配任意长度的任意字符。
  • #:表示匹配任意长度的数字。

我们可以用它们来达成查询任意表或某张表任意一条数据的效果

表示匹配任意表的内容的Uri:**content://com.android.test.provider/***

表示table1表中任意一行的内容的Uri:content://com.android.test.provider/table1/#

查询数据

有了Uri后,我们只需要用它来进行查询就好了。查询后返回的是一个Cursor对象,然后我们就可以将数据从Cursor中逐个取出了。

Cursor cursor = getContentResolver().query(
    uri,
    projection,
    selection,
    selectionArgs,
    sortOrder);

这些参数和SQLite中的参数有点相似。用SQL语句来举例的话,它们都有各自对应的部分

参数名 对应SQL部分
uri from table_name
projection select column1, column2
selection where column = value
selectionArgs -
sortOrder order by column1, column2

添加数据

添加数据就很简单了,构造一个ContentValues,然后用insert方法将它插入就好。

ContentValues values = new ContentValues();
values.put("column1","text");
values.put("column2",1);
getContentResolver().insert(uri,values);

更新数据

更新数据也是非常简单的

ContentValues values = new ContentValues();
values.put("column1","");
getContentResolver().update(uri,values,"column1 = ? and column2 = ?", new String[]{
"text","1"});

删除数据

一样很简单

getContentResolver().update(uri,"column2 = ?",new String[]{"1"});

提供数据:ContentProvider的创建

如果想要在自己的应用中为外部提供接口来达到共享数据的目的,可以新建一个类继承ContentProvider,并重写它的六个抽象方法

  1. onCreate:初始化ContentProvider的时候调用,通常在这里进行数据库的创建和升级。返回true表示ContentProvider初始化成功,返回false则表示失败。
  2. query:从ContentProvider中查询数据,查询的结果存放在Cursor中返回。
  3. insert:向ContentProvider添加一条数据,返回用于表示这条新纪录的Uri。
  4. update:更新ContentProvider已有的数据,返回受影响的行数。
  5. delete:从ContentProvider中删除不数据。返回被删除的行数。
  6. getType:根据传入的Uri返回相应的MIME类型。

UriMatcher

我们可借助UriMatcher来轻松实现匹配内容Uri的功能。它提供了addURI方法,可分别把authority、path以及一个自定义代码传进去。这样,调用UriMatcher的match()方法时,就能传入一个Uri对象,返回匹配这个对象的自定义代码了。利用这个代码,我们就可以判断调用方希望访问哪张表的数据了。

public static final int TABLE1_DIR = 0; 
public static final int TABLE1_ITEM = 1; 
public static final int TABLE2_DIR = 2; 
public static final int TABLE2_ITEM = 3; 
public 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_ITEM);
    uriMatcher.addURI("com.example.app.provider","table2",TABLE2_DIR);
    uriMatcher.addURI("com.example.app.provider","table2/#",TABLE2_ITEM);    
}

实现增删查改方法

比如,我们可以用如下的方法来实现query方法:

@Override
public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder){
    switch(uriMatcher.match(uri)){
        case TABLE1_DIR:
            //查询table1表的所有数据
            break;
        case TABLE1_ITEM:
            //查询table1表的单条数据
            break;
        case TABLE2_DIR:
            //查询table2表的所有数据
            break;
        case TABLE2_ITEM:
            //查询table2表的单条数据
            break;
            ...
    }
    ...
}

除此之外,insert, update, delete这几个方法的实现也是差不多的。

实现getType方法

除增删查改方法外有一个方法需要注意,就是getType方法。它是所有ContentProvider都需要提供的方法,用于获取Uri对象对应的MIME类型。

MIME类型

一个内容URI所对应的MIME字符串主要由三部分组成:

  • 必须以vnd开头
  • 如果内容URI以path结尾,则后接android.cursor.dir/ ,如果以id结尾,则后接android.cursor.item/
  • 最后接上vnd..

因此对于content://com.android.test.provider/table1这个内容Uri,它对应的MIME类型可以写成:

vnd.android.cursor.dir/vnd.com.android.test.provider.table1

对于content://com.android.test.provider/table1/1这个内容Uri,对应的MIME类型就可以写成:

vnd.android.cursor.item/vnd.com.android.test.provider.table1

实现getType方法

有了MIME类型的概念后,我们可以这样实现getType方法:

@Override
public String getType(Uri uri){
    switch(uriMatcher.match(uri)){
        case TABLE1_DIR:
            return "vnd.android.cursor.dir/vnd.com.android.test.provider.table1";
        case TABLE1_ITEM:
            return "vnd.android.cursor.item/vnd.com.android.test.provider.table1";
        case TABLE2_DIR:
            return "vnd.android.cursor.dir/vnd.com.android.test.provider.table2";
        case TABLE1_ITEM:
            return "vnd.android.cursor.item/vnd.com.android.test.provider.table2";
        default:
            break;
    }
    return null;
}

用数据库配合上述方法

一般创建ContentProvider都要配合这个应用的数据库,配合数据库的使用一般是这样的:

  • 在onCreate方法中建立数据库
  • 分别在query insert update delete方法中调用SQLiteDatabase的同名方法来实现。
点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注

%d 博主赞过: