Android四大组件之ContentProvider

一.定义


- 管理对结构化数据集的访问,封装数据并提供用于定义数据安全性的机制.

- ContentProvider是Android系统中提供的专门用户不同应用间进行数据共享的组件,提供了一套标准的接口用来获取以及操作数据,准许开发者把自己的应用数据根据需求开放给其他应用进行增删改查,而无须担心直接开放数据库权限而带来的安全问题。

二.作用

- 进程间进行数据交互 & 共享,就是跨进程通信.也可以进行进程内通信.

- 跨进程通信示意图

三.原理

底层采用的是Android中的Binder机制

四.具体使用

1.统一资源标识符(URI)

(1)定义

- 标识数据的URI, URI包括整个提供程序的符号名称(授权)和一个指向表的名称(路径).
解释
- 外界进程可以通过URI找到对应的ContentProvider&其表内的数据,然后再进行操作

(2)具体使用

- URI 分为 系统预置 和 自定义两种 , 分别对应系统内置的数据(通讯录,日历等) 和自定义数据库
自定义URI

自定义URI

eg:

Uri uri = Uri.parse("content://com.carson.provider/User/1")

- 标明 URI指向的资源是名为 "com.carson.provider"中ContentProvider中的表名为User,ID为1的数据


//特别注意: URI模式存在匹配通配符 * 和 #

/ *:匹配任意长度的任何有效字符的字符串
// 以下的URI 表示 匹配provider的任何内容
	content://com.example.app.provider/* 

// #:匹配任意长度的数字字符的字符串
// 以下的URI 表示 匹配provider中的table表的所有行
	content://com.example.app.provider/table/# 

2.MIME 数据类型

作用

指定某个扩展名的文件用某种应用程序来打开.比如.txt的文件用 text文件打开

(1)ContentProvider 根据 URI 返回MIME的类型

ContentProvider.getType(uri);

(2) MIME 类型组成

每种MIME类型由2个部分组成= 类型+子类型, 就是说
MIME类型是包含了2个部分的字符串

eg:
text/html
application/pdf

(3)MIME类型形式

a.形式1 : 单条记录

	vnd.android.cursor.item/自定义

b.形式2 : 多条记录

	vnd.android.cursor.dir/自定义

//vnd 表示父类型和子类型具有非标准的,特定的形式.
// 父类型已固定好不能更改, 只能区别是单条还是多条记录

3.ContentProvider类

(1) 组织数据方式

ContentProvider 主要以 表格的形式 组织数据,同时也支持文件数据

(2) 主要方法

- 进程间共享数据的本质是: 增删改查数据

- ContentProvider的核心方法也是上述4个作用

eg:

`
<-- 4个核心方法 -->
 public Uri insert(Uri uri, ContentValues values) 
// 外部进程向 ContentProvider 中添加数据

 public int delete(Uri uri, String selection, String[] selectionArgs) 
// 外部进程 删除 ContentProvider 中的数据

 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
// 外部进程更新 ContentProvider 中的数据

 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,  String sortOrder)  
// 外部应用 获取 ContentProvider 中的数据

// 注:
// 1. 上述4个方法由外部进程回调,并运行在ContentProvider进程的Binder线程池中(不是主线程)
// 2. 存在多线程并发访问,需要实现线程同步
	// a. 若ContentProvider的数据存储方式是使用SQLite & 一个,则不需要,因为SQLite内部实现好了线程同步,若是多个SQLite则需要,因为SQL对象之间无法进行线程同步
	// b. 若ContentProvider的数据存储方式是内存,则需要自己实现线程同步

<-- 2个其他方法 -->
public boolean onCreate() 
// ContentProvider创建后 或 打开系统后其它进程第一次访问该ContentProvider时 由系统进行调用
// 注:运行在ContentProvider进程的主线程,故不能做耗时操作

public String getType(Uri uri)
// 得到数据类型,即返回当前 Url 所代表数据的MIME类型

注:

ContentProvider类并不会直接与外部进程交互,而是通过ContentResolver 类

4.ContentResolver类

(1).作用

统一管理不同ContentProvider间的操作
a. 通过URI即可操作不同ContentProvider中的数据
b. 外部进程通过ContentResolver类与ContentProvider进行交互.

(2)为什么不直接只用ContentProvider进行交互,中间还加了一层ContenResolver?###

a. 如果app要和多个ContentProvider进行交互,实现不同的ContentProvider再完成数据交互,操作成本高难度也大.
b. 所以在ContentProvider类上再加上一层ContentResolver类对所有的ContentProvider类进行统一管理.

(3)具体使用

核心方法:

`
// 外部进程向 ContentProvider 中添加数据
public Uri insert(Uri uri, ContentValues values)  

// 外部进程 删除 ContentProvider 中的数据
public int delete(Uri uri, String selection, String[] selectionArgs)

// 外部进程更新 ContentProvider 中的数据
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)  

// 外部应用 获取 ContentProvider 中的数据
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
`

eg:

`
// 使用ContentResolver前,需要先获取ContentResolver
// 可通过在所有继承Context的类中 通过调用getContentResolver()来获得ContentResolver
ContentResolver resolver =  getContentResolver(); 

// 设置ContentProvider的URI
Uri uri = Uri.parse("content://cn.scu.myprovider/user"); 

// 根据URI 操作 ContentProvider中的数据
// 此处是获取ContentProvider中 user表的所有记录 
Cursor cursor = resolver.query(uri, null, null, null,"userid desc"); 

5.ContentUris类

作用

	操作URI

核心方法

	withAppendedId()
	parseId()

eg:

`// 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); 
//获取的结果为:7 
`

6.UriMatcher类

作用

- 在ContentProvider注册 URI
- 根据URI匹配ContentProvider中对应的数据表

eg:

`
// 步骤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:根据URI 匹配 URI_CODE,从而匹配ContentProvider中相应的资源(match())

@Override   
public String getType(Uri uri) {   
  Uri uri = Uri.parse(" content://cn.scu.myprovider/user1");   

  switch(matcher.match(uri)){   
 // 根据URI匹配的返回码是URI_CODE_a
 // 即matcher.match(uri) == URI_CODE_a
  case URI_CODE_a:   
    return tableNameUser1;   
    // 如果根据URI匹配的返回码是URI_CODE_a,则返回ContentProvider中的名为tableNameUser1的表
  case URI_CODE_b:   
    return tableNameUser2;
    // 如果根据URI匹配的返回码是URI_CODE_b,则返回ContentProvider中的名为tableNameUser2的表
}   
}

7.ContentObserver类

内容观察者

作用:

观察ContentProvider中的数据变化(增删改) & 通知外界

eg:

`
// 步骤1:注册内容观察者ContentObserver
getContentResolver().registerContentObserver(uri);
// 通过ContentResolver类进行注册,并指定需要观察的URI

// 步骤2:当该URI的ContentProvider数据发生变化时,通知外界(即访问该ContentProvider数据的访问者)
public class UserContentProvider extends ContentProvider { 
  public Uri insert(Uri uri, ContentValues values) { 
  db.insert("user", "userid", values); 
  getContext().getContentResolver().notifyChange(uri, null); 
  // 通知访问者
 } 
}

// 步骤3:解除观察者
getContentResolver().unregisterContentObserver(uri);
// 同样需要通过ContentResolver类进行解除

总结图

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值