内容提供器---Content Provider

Content Provider

内容提供者主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性。目前,使用内容提供者是Android实现跨程序共享数据的标准方式。不同于文件存储和SharedPreferences存储中的两种全局可读写操作模式,内容提供器可以选择只对哪一部分数据进行共享,从而保证我们程序中的隐私数据不会被泄露的风险。

内容提供器的用法一般有两种,一种是使用现有的内容提供器来读取和操作相应程序中的数据,另一种是创建自己的内容提供器给我们程序提供外部访问接口。

访问其他程序中的数据

对于每一个应用程序来说,如果想要访问内容提供器中共享的数据,就一定要借助ContentResolve类,可以通过Context中的getContentResolver()方法获取到该类的实例。ContentResolver中提供了一系列的方法用于对数据进行增删改查操作。insert()、update()、delete()、query()等方法。

URI 内容URI给内容提供器中的数据建立了唯一标识符,主要由两部分组成,权限(authority)和路径(path)。权限是用于对不同的应用程序做区分的,一般为了避免冲突,都会采用程序包名的方式来进行命名。路径则是用于对同一应用程序中不同的表做区分的,通常都会添加到权限的后面。

URL最标准的格式写法如下:
content://com.example.app.provider/table1

解析成Uri对象才可以作为参数传入,解析的方法也相当简单,代码如下:
Uri uri =Uri.parse(“content://com.example.app.provider/table1”);

增、删、改、查

Cursor cursor =getContentResolver().query(
    uri,  //Uri 对象
    projection, //要查询的列名
    selection,  //约束条件
    selectionArgs, //约束条件及其值
    sortOrder  //指定查询结果的排序方式
    );
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().delete(uri,"column2 = ?",new String[]{"1"});

创建自己的内容提供器

提供给外部访问接口的应用程序都是如何实现增删改查,并且保证共享数据的安全的呢?下面我们继续探究。

继承ContentProvider类

public class MyProvider extends ContentProvider{
    public boolean onCreate(){
        return false;
    }

    public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder){
        return null;
    }

    public Uri insert(Uri uri,ContentValues values){
        return null;
    }

    public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs){
        return 0;
    }

    public int delete(Uri uri,String selection,String[] selectionArgs){
        return 0;
    }

    public String getType(){
        return null;
    }
}

onCreate()
    初始化内容提供器的时候调用。通常会在这里完成对数据库的创建和升级等操作,返回true表示内容提供器初始化成功,返回false则表示失败。注意,只有当存在ContentResolver尝试访问我们程序中的数据时,内容提供器才会被初始化。

query()
    从内容提供器中查询数据。使用uri参数来确定查询哪张表,projection参数用于确定查询哪些列,selection和seletionArgs参数用于约束查询哪些行,sortOrder参数用于对结果进行排序,查询的结果存放在Cursor对象中返回。

insert()
    向内容提供器中添加一条数据。使用uri参数来确定要添加到的表,待添加的数据保存在values参数中。添加完成后,返回一个用于表示这条新记录的URI。

update()
    更新内容提供器中已有的数据,返回的结果是受影响的行数将作为返回值返回。

delete()
    从内容提供器中删除数据。被删除的行数将作为返回值返回。
getType()
    根据传入的内容URI来返回相应的MIME类型。

匹配

使用通配符的方式来分别匹配这两种格式的内容URI,规则如下。
1、*:表示匹配任意长度的任意字符
2、#:表示匹配任意长度的数字
    所以,一个能够匹配任意表的内容URI格式就可以写成:
        content://com.example.app.provider/*
        而一个能够匹配table1表中任意一行数据的内容URI格式就可以写成:
        content://com.example.app.provider/table1/#

我们借助UriMatcher这个类就可以轻松地实现匹配内容URI的功能。UriMatcher中提供一个addURI()方法,这个方法接收三个参数,可以分别把权限、路径和一个自定义代码传进去。这样,当调用UriMatcher的match()方法时,就可以将一个Uri对象传入,返回值是某个能够匹配这个Uri对象所对应的自定义代码,利用这个代码,我们就可以判断出调用方期望访问的是哪张表中的数据了。


public class MyProvider extends ContentProvider{
    public static final int TABLE_DIR=0;
    public static final int TABLE_ITEM=1;
    public static final int TABLE2_DIR =2;
    public static final int TABLE2_ITEM=3;
    static{
        uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI("com.example.app.provider","table1",TABLE1_DIR);
        uriMatcher.addURI("com.example.app.provider","table1/#",TABLE_ITEM);
        uriMatcher.addURI("com.example.app.provider","table2",TABLE2_ITEM);
        uriMatcher.addURI("com.example.app.provider","table2/#",TABLE2_ITEM);
    }

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

getType()方法。它是所有的内容提供器都必须提供的一个方法,用于获取Uri对象所对应的MIME类型。一个内容URI所对应的MIME字符串主要由三个部分组成,Android 对这三个部分做了如下格式规定。
1、必须以vnd开头。
2、如果内容URI以路径结尾,则后接android.cursor.dir/,如果内容URI以id结尾,则后接android.cursor.item/。
3、最后接vnd.<authority>.<path>
如:对于content://com.example.app.provider/table1这个内容URI,它所对应的MIME类型就可以写成:
vnd.android.cursor.dir/vnd.com.example.app.provider.table1

getType()逻辑:

public String getType(Uri uri){
    switch(uriMatcher.match(uri)){
        case TABLE_DIR:
            return "vnd.android.cursor.dir/vnd/com.example.app.provider/table1";
        case TABLE_ITEM:
            return "vnd.android.cursor.item/vnd.com.example.app.provider.table1";
        case TABLE2_DIR:
            return "vnd.android.cursor.dir/vnd.com.example.app.provider.table2";
        case TABLE2_ITEM:
            return "vnd.android.cursor.item/vnd.com.example.app.provider.table2";
        default:
            break;
    }
    return null;
}
注:
String bookId = uri.getPathSegments().get(1);
updatedRows = db.update("Book",values,"id = ?",new String[]{bookId});
当访问单条数据的时候,这里调用了Uri对象的getPathSegments()方法,它会将内容URI权限之后的部分以“/”符号进行分割,并把分割后的结果放入到一个字符串列表中,那这个列表的第0个位置存放的就是路径,第1个位置存放的就是id了。得到了id之后,再通过selection和selectionArgs参数进行约束,就实现了查询单条数据的功能。
内容提供器注册

全类名+权限

<provider 
    android:name="com.example.databasetest.DatabaseProvider"
    android:authorities="com.example.databasetest.provider">
</provider>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值