ContentPriver
共享应用程序内的数据, 在数据修改时可以监听
1、特点
①、可以将应用中的数据对外进行共享;
②、数据访问方式统一,不必针对不同数据类型采取不同的访问策略;
③、内容提供者将数据封装,只暴露出我们希望提供给其他程序的数据(这点有点类似Javabeans);
④、内容提供者中数据更改可被监听;
2、创建内容提供者
- 定义类继承ContentProvider,根据需要重写其内容方法(6个方法):
l onCreate() 创建内容提供者时,会调用这个方法,完成一些初始化操作;
l crud相应的4个方法 用于对外提供CRUD操作;
l getType() 返回当前Url所代表数据的MIME类型:
返回的是单条记录:以vnd.android.cursor.item/ 开头,如:vnd.android.cursor.item/person
返回的是多条记录:以vnd.android.cursor.dir/ 开头,如:vnd.android.cursor.dir/person
- 在清单文件的<application>节点下进行配置,<provider>标签中需要指定name、authorities、exported属性
l name: 为全类名;
l authorities: 是访问Provider时的路径,要唯一;
l exported: 用于指示该服务是否能够被其他应用程序组件调用或跟它交互
- URI代表要操作的数据,由scheme、authorites、path三部分组成:
l content://com.itheima.sqlite.provider/person
l scheme: 固定为content,代表访问内容提供者;
l authorites: <provider>节点中的authorites属性;
l path: 程序定义的路径,可根据业务逻辑定义;
- 操作 URI的UriMather与ContentUris工具类:
当程序调用CRUD方法时会传入Uri
l UriMatcher:表示URI匹配器,可用于添加Uri匹配模式,与匹配Uri(见下代码);
l ContentUris:用于操作Uri路径后面的ID部分,2个重要的方法:
- withAppendedId(uri, id) 为路径加上ID部分;
- parseId(uri) 用于从路径中获取ID部分;
示例代码(内容提供者类):
public class HeimaProvider extends ContentProvider {
private static final int PERSON = 1; // 匹配码
private static final int STUDENT = 2; // 匹配码
private static final int PERSON_ID = 3; // 匹配码
private MyHelper helper;
/** Uri匹配器 */
private UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
@Override
public boolean onCreate() {
System.out.println("onCreate...");
helper = new MyHelper(getContext());
// == 添加 uri 匹配模式, 设置匹配码(参数3) Uri如果匹配就会返回相应的匹配码 ==
uriMatcher.addURI("com.itheima.sqlite.provider", "person", PERSON);
uriMatcher.addURI("com.itheima.sqlite.provider", "#", PERSON_ID); // #表示匹配数字,*表示匹配文本
uriMatcher.addURI("com.itheima.sqlite.provider", "student", STUDENT);
return true;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = helper.getWritableDatabase();
switch (uriMatcher.match(uri)) { // 匹配uri
case PERSON:
long id = db.insert("person", "id", values);
db.close();
return ContentUris.withAppendedId(uri, id); // 在原uri上拼上id,生成新的uri并返回;
case STUDENT:
long insert = db.insert("student", "id", values);
System.out.println("数据文件中,没有student表,也不会报错");
db.close();
return ContentUris.withAppendedId(uri, insert); // 为路径上,加上ID
default:
throw new IllegalArgumentException(String.format("Uri:%s 不是合法的uri地址", uri));
}
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = helper.getWritableDatabase();
switch (uriMatcher.match(uri)) { // 匹配uri
case PERSON_ID:
long parseId = ContentUris.parseId(uri); // 获取传过来的ID值
selection = "id=?"; // 设置查询条件
selectionArgs = new String[] { parseId + "" }; // 查询条件值
case PERSON:
int delete = db.delete("person", selection, selectionArgs);
db.close();
return delete;
default:
throw new IllegalArgumentException(String.format("Uri:%s 不是合法的uri地址", uri));
}
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
SQLiteDatabase db = helper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case PERSON_ID:
long parseId = ContentUris.parseId(uri); // 获取传过来的ID值
selection = "id=?"; // 设置查询条件
selectionArgs = new String[] { parseId + "" }; // 查询条件值
case PERSON:
int update = db.update("person", values, selection, selectionArgs);
db.close();
return update;
default:
throw new IllegalArgumentException(String.format("Uri:%s 不是合法的uri地址", uri));
}
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = helper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case PERSON_ID:
// == 根据ID查询 ==
long parseId = ContentUris.parseId(uri); // 获取传过来的ID值
selection = "id=?"; // 设置查询条件
selectionArgs = new String[] { parseId + "" }; // 查询条件值
case PERSON:
Cursor cursor = db.query("person", projection, selection, selectionArgs, null, null, sortOrder);
// == 注意:此处的 db与cursor不能关闭 ==
return cursor;
default:
throw new IllegalArgumentException(String.format("Uri:%s 不是合法的uri地址", uri));
}
}
// 返回传入URI的类型,可用于测试URI是否正确
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case PERSON_ID:
return "vnd.android.cursor.item/person"; // 表示单条person记录
case PERSON:
return "vnd.android.cursor.dir/person"; // 表单多个person记录
default:
return null;
}
}
}
清单中的配置:
<provider
android:exported="true"
android:name="com.itheima.sqlite.provider.HeimaProvider"
android:authorities="com.itheima.sqlite.provider" />
authorities 可以配置成如下形式(系统联系人的):
android:authorities="contacts;com.android.contacts"
“;” 表示的是可使用 contacts, 与 com.android.contacts
3、内容解析者ContentResolver
通过Context获得ContentResolver内容访问者对象(内容提供者的解析器对象);
调用ContentResolver对象的方法即可访问内容提供者
测试类代码:
public class HeimaProviderTest extends AndroidTestCase {
/** 测试添加数据 */
public void testInsert() {
ContentResolver resolver = this.getContext().getContentResolver();
Uri uri = Uri.parse("content://com.itheima.sqlite.provider/person");
ContentValues values = new ContentValues();
values.put("name", "小翼");
values.put("balance", 13000);
Uri insert = resolver.insert(uri, values); // 获取返回的uri,如:content://com.itheima.sqlite.provider/7
System.out.println(insert);
}
/** 测试删除 */
public void testRemove() {
ContentResolver resolver = this.getContext().getContentResolver();
Uri uri = Uri.parse("content://com.itheima.sqlite.provider/person");
int count = resolver.delete(uri, "id=?", new String[] { 3 + "" });
System.out.println("删除了" + count + "行");
}
/** 测试更新 */
public void testUpdate() {
ContentResolver resolver = this.getContext().getContentResolver();
Uri uri = Uri.parse("content://com.itheima.sqlite.provider/person");
ContentValues values = new ContentValues();
values.put("name", "小赵 update");
values.put("balance", 56789);
int update = resolver.update(uri, values, "id=?", new String[] { 6 + "" });
System.out.println("更新了" + update + "行");
}
/** 测试查询 */
public void testQueryOne() {
ContentResolver resolver = this.getContext().getContentResolver();
Uri uri = Uri.parse("content://com.itheima.sqlite.provider/person");
Cursor c = resolver.query(uri, new String[] { "name", "balance" }, "id=?", new String[] { 101 + "" }, null);
if (c.moveToNext()) {
System.out.print(c.getString(0));
System.out.println(" " + c.getInt(1));
}
c.close();
}
/**测试查询全部 */
public void testQueryAll() {
ContentResolver resolver = this.getContext().getContentResolver();
Uri uri = Uri.parse("content://com.itheima.sqlite.provider/person");
Cursor c = resolver.query(uri, new String[] { "id", "name", "balance" }, null, null, "name desc");
while (c.moveToNext()) {
System.out.println(c.getInt(0) + ", " + c.getString(1) + ", " + c.getInt(2));
}
c.close();
}
/** 测试查询一条 */
public void testQueryOneWithUriId() {
ContentResolver resolver = this.getContext().getContentResolver();
Uri uri = Uri.parse("content://com.itheima.sqlite.provider/3"); // 查询ID为3的记录
Cursor c = resolver.query(uri, new String[] { "id", "name", "balance" }, null, null, null);
if (c.moveToNext()) {
System.out.println(c.getInt(0) + ", " + c.getString(1) + ", " + c.getInt(2));
}
c.close();
}
/** 测试获取内容提供者的返回类型 */
public void testGetType() {
ContentResolver resolver = this.getContext().getContentResolver();
System.out.println(resolver.getType(Uri.parse("content://com.itheima.sqlite.provider/2")));
System.out.println(resolver.getType(Uri.parse("content://com.itheima.sqlite.provider/person")));
}
}
4、监听内容提供者的数据变化
在内容提供者中可以通知其他程序数据发生变化
通过Context的getContentResolver()方法获取ContentResolver
调用其notifyChange()方法发送数据修改通知,发送到系统的公共内存(消息信箱中)
在其他程序中可以通过ContentObserver监听数据变化
通过Context的getContentResolver()方法获取ContentResolver
调用其registerContentObserver()方法指定对某个Uri注册ContentObserver
自定义ContentObserver,重写onChange()方法获取数据
示例代码(发通知部分):
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = helper.getWritableDatabase();
int delete = db.delete("person", selection, selectionArgs);
// == 通过内容访问者对象ContentResolve 发通知给所有的Observer ==
getContext().getContentResolver().notifyChange(uri, null);
db.close();
return delete;
}
}
监听部分:
// 注册内容观察者事件
private void initRegisterContentObserver() {
Uri uri = Uri.parse("content://com.itheima.sqlite.provider"); // 监听的URI
// == 第2个参数:true表示监听的uri的后代都可以监听到 ==
getContentResolver().registerContentObserver(uri, true, new ContentObserver(new Handler()) {
public void onChange(boolean selfChange) { // 接到通知就执行
personList = personDao.queryAll();
((BaseAdapter) personListView.getAdapter()).notifyDataSetChanged();
}
});
}
5、区别Provider/Resolver/Observer
1)ContentProvider:内容提供者
把一个应用程序的私有数据(如数据库)信息暴露给别的应用程序,让别的应用程序可以访问;
在数据库中有对应的增删改查的方法,如果要让别的应用程序访问,需要有一个路径uri:
通过content:// 路径对外暴露,uri写法:content://主机名/表名
2)ContentResolver:内容解析者
根据内容提供者的路径,对数据进行操作(crud);
3)ContentObserver:内容观察者
可以理解成android系统包装好的回调,数据发送变化时,会执行回调中的方法;
ContentResolver发送通知,ContentObserver监听通知;
当A的数据发生变化的时候,A就会显示的通知一个内容观察者,不指定观察者,就会发消息给一个路径
ContentPriver的更多相关文章
- SQLite数据库与Contentprovider(2)
ContentProvider: 在创建ContentProvider时,需要首先使用数据库.文件系统或网络实现底层存储功能, 然后在继承ContentProvider的类中实现基本数据操作的接口函数 ...
随机推荐
- fread和fwrite函数功能
fread和fwrite函数功能 用来读写一个数据块. 一般调用形式 fread(buffer,size,count,fp); fwrite(buffer,size,count,fp); ...
- hdu1495(经典bfs,平分水问题)
思路:搜索题,第一次做这种类型的题目吧,一开始表示不怎么明白题意所说的东东.其实就是要你判断可乐能不能被平分........ 有六种状态,从a瓶到b瓶,a-->c b-->a b- ...
- 我的电脑(ACER 4750G)升级
升级原因 近期电脑卡的要死,卡到什么程序呢?就是打开"我的电脑"须要2秒中的缓冲时间,这怎样受的了--于是就有种特别想换电脑的冲动:买一个顶配版的台式机.让你给我慢. 一心想着顶配 ...
- 【Unity笔记】鼠标射线由指定层接收
LayerMask mask = << LayerMask.NameToLayer("UI"); Ray ray = Camera.main.ScreenPointTo ...
- 关于JXL读写以及修改EXCEL文件<转>
首先引用网上的文章,谈谈JXL与POI的区别 POI为apache公司的一个子项目,主要是提供一组操作windows文档的Java API. Java Excel俗称jxl是一开放源码项目,通过它Ja ...
- 9260与SAM-BA连接(转)
对于AT91SAM9260的bootloader的烧写,常常会遇到这样的问题:对于干净的NAND FLASH(即没有烧写过任何东西),AT91SAM9260与sam-ba很容易连接成功,但当烧写过bo ...
- MySQL下查询锁信息
SHOW PROCESSLIST;SHOW OPEN TABLES WHERE In_use > 0; #运行线程 SHOW GLOBAL STATUS LIKE 'Threads_runn ...
- Qt学习之路(tip): parent参数
这是一篇很简单的文章,仅仅是用来说明一下一个参数的作用,因此我把它写成了tip,而不是接下来的17. 程序写的多了,你会发现几乎所有的Qt类的构造函数都会有一个parent参数.这个参数通常是QO ...
- VMware提示:已将该虚拟机配置为使用 64 位客户机操作系统。但是,无法执行 64 位操作。解决方案
新买了个笔记本,在学习大数据的时候装上VMWare,运行虚拟机发现提示无法执行64位操作.本人系统是win7,64位系统. 之后就是一顿度娘,发现千篇一律都是检测CPU支不支持虚拟化,支持的话去BIO ...
- 在CentOS上以源码编译的方式安装Greenplum数据库
集群组成: 一台主机,一台从节点. 系统环境: 操作系统:CentOS 7,64位,7.4.1708(/etc/redhat-release中查看) CPU:AMD Fx-8300 8核 内存:8GB ...