ContentProvider

 基础
一个ContentProvider 一般是供其它程序访问的,它提供了 跨进程的能力.
一个Provider的表格并不要求必须有一个 _ID 列,不过如果想要把查询的数据在ListView中显示,则必须有 _ID 列.

2 ContentResolver与ContentProvider
Resolver能够解析Uri,根据Uri能够找到其对应的provider,并把query/insert/update/delete操作传递给它,如下图:


ContentResolver的查询方法如下:
public final Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
/*

uri: 指明了ContentProvider的Authority,及此Authority下的表
projection:需要查询哪些列 即 select [projection1,projection2] from table
selection: 即 where a=? and b=?
selectionArgs: 即对应selection语句中的两个 ?
sortOrder:比如为 columnName1 DESC  //ASC升序 默认  DESC 降序

*/

一个例子 URI 如下:

content://user_dictionary/words
其中 content 为scheme, user_dictionary 为authory(<provider>自己声明的),words为path(也可理解为表名或单个行)

下面为一个构造Uri的一个小方法:(使 path 部分指向单独的一行)

Uri singleUri = ContentUri.withAppendedId(UserDictionary.Words.CONTENT_URI,4);


3 ContentProvider permission

However, components in the provider's application always have full read and write access, regardless of the specified permissions.

这句话说,和 ContentProvider 在同一个包内的应用程序有所有的权限访问Provider, Provider的permisson对同一个包内的程序不起作用.(这一点在NotePad例子程序中得到体现)

在定义一个 Provider 时需要声明它的permission, 但它的权限声明方法和其它组件不同, 它是使用 <android:readPermission><android:writePermission>及<android:grantUriPermission>, 同时 <permission> 指打开读写权限.  具体可以参考 App Component 中的 Permission 一节(有博客).


4 insert/update/delete 时会用到 ContentValues 类作为一个工具类, 很好理解,不多述.


5 我们知道 MIME 类型在 <intent-filter> 中会用到, 一个 ContentProvider也会声明自己的 MIME 类型,这个 MIME 类型有什么用呢?

文档上说,你的APP可以根据 Provider的MIME类型来决定是否能够解析它的内容,对 Provider 的 MIME 类型的作用还不是很明白! 但有下面一些总结. 你想访问ContentProvider就必须要提供一个 Uri, 对于 ContentProvider来说, 过来一个 Uri 它就会返回一些值, 那么返回的这些值是什么类型的呢? 它应该进行说明一下. 所以 ContentProvider 的一个 Uri就对应一个 MIME 类型.  一些规范的 MIME 类型很少用到, 比如说 text/html,  在 Provider里暂时没有发现这种用法. 但自己确可以定义自己的 MIME 类型, 方法如下:

自定义的 MIME 类型的主类型必须是

vnd.android.cursor.dir //代表多行数据

vnd.android.cursor.item  //代表单行数据
而子类型则可以根据表名来定义,下面是一个例子:

Uri :

content://com.example.trains/Line1 //Line1 为一个表
的 MIME 为:

vnd.android.cursor.dir/vnd.example.line1   //vnd.example.line1是自己取的名

Uri

content://com.example.trains/Line2/5
的MIME为:

vnd.android.cursor.item/vnd.example.line2

6 访问ContentProvider的方法种类

共有三种: batch 访问(略), CursorLoader的异步访问(略), Intent 访问

一个 ContentProvider 并不接受 Intent 的访问方式, 但是和ContentProvider在一个包内的相关APP确可以接受 Intent,通过这个APP,外部的APP就可以得到想要的结果.

这样特定的 Intent 必须包含 FLGA:

FLAG_GRANT_READ_URI_PERMISSION 或 FLAG_GRANT_WRITE_URI_PERMISSION
同时, ContentProvider 也必须通过 <android:grantUriPermission> 或 <grant-permission> 声明 Uri 访问权限.

下面是一个例子:


7 一般情况下, 不必新建 ContentProvider,  你的程序如果需要使用 SQLiteDatabase, 直接使用即可,不用通过 ContentProvider. 只有具有一些供其它程序访问的数据时才需要自己建立一个 ContentProvider. (NotePad 例子应该是个例外,它只是为了展示ContentProvider的用法)


8 建立 ContentProvider 的步骤

1> 确定底层存储方式,是文件还是数据库或其它形式

2> 继承 ContentProvider , 并实现必须的方法

3> 定义好你自己ContentProvider的 authority 及 URI

其实上述步骤并没有先后, 总之就是  先设计好 存储格式(更多是表的格式), 再设计好 Authority, 表的列, 最后实现 ContentProvider子类中的方法.

设计 ContentProvider时 UriMatcher 可以提供帮助,  有两个通配符需要了解:

*: Matches a string of any valid characters of any length.
#: Matches a string of numeric characters of any length.
 

假设你准备了以下的 URI:

content://com.example.app.provider/table1: A table called table1.
content://com.example.app.provider/table2/dataset1: A table called dataset1.
content://com.example.app.provider/table2/dataset2: A table called dataset2.
content://com.example.app.provider/table3: A table called table3.

则 content://com.example.app.provider/* 匹配所有的 URI, content://com.example.app.provider/table2/* 匹配 dataset1和dataset2,

content://com.example.app.provider/table3/#  匹配 content://com.example.app.provider/table/6 这种形式

下面是 UriMatcher的应用的例子:

sUriMatcher.addURI("com.example.app.provider", "table3", 1);
sUriMatcher.addURI("com.example.app.provider", "table3/#", 2);


switch (sUriMatcher.match(uri)) {
            // If the incoming URI was for all of table3
            case 1:
                if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";
                break;
            // If the incoming URI was for a single row
            case 2:
                ...
}


继承 ContentProvider 的类必须实现的方法有:

query( )

insert( )

update( )

delete( )

getType( )

//以上五个方法必须注意多线程问题

onCreate( ) : 此方法应该简洁,以尽快返回,使调用者得到快带的回应(SQLiteOpenHelper会把创建数据库的时间推迟到必须要对数据库进行操作时)


getType( ) 方法特别说明:

自定义 MIME 类型应该是:

vnd.android.cursor.dir/vnd.<name>.<type> 或

vnd.android.cursor.item/vnd.<name>.<type>

其中红色部分为固定不变的 <name>可以为包名, type 可以为表名, 例子如下:

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

vnd.android.cursor.item/vnd.com.example.provider.table1 (for 单独的一行)

MIME for file / getStreamType( ) 暂不学习



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值