Android学习笔记2-1--组件2--Provider
来源:互联网 发布:淘宝活动时间表 编辑:程序博客网 时间:2024/06/11 15:59
组件简介
ContentProvider将程序内部数据向其他程序公开。ContentResolver对程序内部数据进行CRUD操作。需要通过ContentResolver对象传递URI间接调用ContentProvider。
通过ContentResolver访问ContentProvider。在发起的一个请求的过程中,Android系统根据URI确定处理这个查询的ContentProvider,然后初始化ContentProvider所有需要的资源(这个初始化的工作是Android系统完成)。一般情况下只有一个ContentProvider对象,但却可以同时与多个ContentResolver进行交互。
ContentProvider完全屏蔽了底层数据源的数据存储方法。数据提供者通过ContentProvider提供了一组标准的数据操作接口,但却无须知道数据提供者的内部数据的存储方法。数据提供者可以使用SQLite数据库存储数据,也可以通过文件系统或SharedPreferences存储数据,甚至是使用网络存储的方法,这些数据的存储方法和存储设备对数据使用者都是不可见的。正是这种屏蔽模式很大程度上简化了ContentProvider的使用方法,使用者只要调用ContentProvider提供的接口函数即可完成所有的数据操作,而数据存储方法则是ContentProvider设计者需要考虑的问题。
ContentProvider的数据集类似于数据库的数据表。每行是一条记录且每列具有相同的数据类型,每条记录都包含一个长整型的字段_ID用来唯一标识每条记录。ContentProvider可以提供多个数据集,调用者使用URI对不同数据集的数据进行操作。
URI是一个用于标识某一互联网资源名称的字符串。URI标识允许用户对任何(包括本地和互联网)的资源通过特定的协议进行交互操作。ContentProvider使用的URI语法结构如下:
content://<authority>/<data_path>/<id># 例如:content://cn.hisuites.andr.test.xxx.provider/people/girl/3# content://是通用前缀,表示该UIR用于ContentProvider定位资源。# <authority>是授权名称,用来确定具体由哪一个ContentProvider提供资源。# <data_path>是数据路径,用来确定请求的是哪个数据集。数据集的数据路径可以写成多段格式,如people/girl和people/boy。如果ContentProvider仅提供一个数据集,数据路径则可以省略;如果ContentProvider提供多个数据集,数据路径必须指明具体数据集。# <id>是数据编号,用来唯一确定数据集中的一条记录,匹配数据集中_ID字段的值。如果请求的数据不只一条,<id>可以省略。
组件定义
DEMO看这里。
组件声明
# 实现类为TProvider# 授权者名称为cn.hisuites.andr.test.xxx.provider的ContentProvider# exported的true为可被外部程序访问<provider android:name=".model.TProvider" android:authorities="cn.hisuites.andr.test.xxx.provider" android:exported="true"/>
组件方法
ContentProvider也是继承ComponentCallbacks2,有些方法参考Contenxt。
# 一般用来初始化底层数据集和建立数据连接等工作。true表示初始化成功,false表示初始化失败public boolean onCreate()# 用来返回指定URI的MIME数据类型。# 若URI是单条数据,则返回的MIME数据类型以vnd.android.cursor.item开头。# 若URI是多条数据,则返回的MIME数据类型以vnd.android.cursor.dir/开头。public String getType(...)# 用于对数据集的增删改查操作,注意,在正确操作获取结果后有个结尾public Uri insert(...)public int delete(...)public int update(...)public Cursor query(...# 结尾getContext().getContentResolver().notifyChange(uri, null);
在正确操作后有个结尾,也可以看本文后面的Observer。
辅助工具
UriMatcher
UriMatcher本质上是一个文本过滤器,用在contentProvider中帮助我们过滤,分辨出查询者想要查询哪个数据表。
static{ # 构造函数中,UriMatcher.NO_MATCH是URI无匹配时的返回代码值为-1 uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); # addURI方法用来添加新的匹配项 uriMatcher.addURI(AUTHORITY, PATH_MULTIPLE, MULTIPLE_PEOPLE); uriMatcher.addURI(AUTHORITY, PATH_SINGLE, SINGLE_PEOPLE);}# authority表示匹配的授权者名称,path表示数据路径(#代表任何数字),code表示返回代码public void addURI(String authority, String path, int code);# 在getType中使用例子:@Overridepublic String getType(Uri uri) { switch(uriMatcher.match(uri)){ case MULTIPLE_PEOPLE: //多条数据的处理 break; case SINGLE_PEOPLE: //单条数据的处理 break; default: throw new IllegalArgumentException("不支持的URI:" + uri); }}
ContentUris
ContentUris是content URI的一个辅助类。它有两个方法很有用,具体如下所示。
# 把content URI后边的id解析出来public static long parseId(Uri contentUri)# 把id和contentUri连接成一个新的Uripublic static Uri withAppendedId(Uri contentUri, long id)
组件使用
通过ContentResolver访问ContentProvider。每个Android组件都有一个ContentResolver对象,通过调用getContentResolver()方法可得到ContentResolver对象。
# 准备ContentResolver resolver = getContentResolver();String CONTENT_URI = "xxxxxxx";String KEY_ID = "_id";String KEY_NAME = "name";String KEY_AGE = "age";String KEY_HEIGHT = "height";# 增加:通过insert()函数添加单条数据ContentValues values = new ContentValues();values.put(KEY_NAME, "Tom");values.put(KEY_AGE, 21);values.put(KEY_HEIGHT, 1.81f);Uri newUri = resolver.insert(CONTENT_URI, values);# 添加:通过bulkInsert()函数添加多条数据ContentValues[] arrayValues = new ContentValues[10]; //实例化每一个ContentValues...int count = resolver.bulkInsert(CONTENT_URI, arrayValues );# 删除:通过delete语句删除一条或多条数据Uri uri = Uri.delete(CONTENT_URI + "/" +"2");String deleteVal = null;int result = resolver.delete(uri, deleteVal, null);# 删除:通过selection语句删除一条或多条数据Uri uriVal = Uri.parse(CONTENT_URI);String deleteVal = KEY_ID + ">4";int result = resolver.delete(uriVal, deleteVal, null);# 修改Uri uriVal = Uri.parse(CONTENT_URI + "/" + "2");ContentValues updateVal = new ContentValues();values.put(KEY_NAME, "Tom");values.put(KEY_AGE, 21);values.put(KEY_HEIGHT, 1.81f);int result = resolver.update(uriVal, updateVal, null, null);# 查询Uri uriVal = Uri.parse(CONTENT_URI + "/" + "2");String[] queryVal = new String[]{KEY_ID, KEY_NAME, KEY_AGE, KEY_HEIGHT};Cursor cursor = resolver.query(uriVal, queryVal, null, null, null);# 在URI中定义了需要查询数据的ID后,在query()函数中没有必要再加入其他的查询条件。# 如果要获取数据集全部数据,则可以直接使用CONTENT_URI且不加查询条件。
ContentProvider的查询结果的返回值是数据集的指针Cursor类。在提取Cursor数据中的数据前,推荐测试Cursor中的数据数量,避免在数据获取中产生异常。
int resultCounts = cursor.getCount();if(resultCounts == 0 !cursor.moveToFirst()){ return null;}//...
如何监听数据变化
不管是ContentProvider中实现的方法中的任何一个,程序都会调用getContext().getContentResolver().notifyChange(uri,null);这行代码可用于通知所有注册在该Uri上的监听者该ContentProvider所共享的数据发生了改变。本质是通过ContentResolver为ContentProvider注册一个ContentObserver。
方法是调用ContentResolver的registerContentObserver方法为其注册个ContentObserver。当它所监听的ContentProvider所共享的数据发生改变时,该onChange将会触发。
getContentResolver().registerContentObserver(Uri uri,boolean notifyForDescendents,ContentObserver observer)# notifyForDescendents参数:# 如果参数为false,那么只有content://abc的数据改变时会触发该监听器。# 如果该参数设为true,假如Uri为content://abc,那么Uri为content://abc/xyz, content://abc/xyz/foo的数据改变时也会触发该监听器。
请注意:ContentResolver运行在主线程中。ContentResolver并不是一个新的线程,也不是新的进程。也就是说,若您需要在ContentResolver中执行较为耗时的操作(如播放音乐、执行网络请求等),需要在ContentResolver中创建一个新的线程。这可以防止ANR的发生,同时主线程可以执行正常的UI操作。
也可通过Cursor.setNotificationUri间接的注册一个ContentObserver,具体的后续再看。
最后,可以看看这篇文章,很不错。
- Android学习笔记2-1--组件2--Provider
- Android学习笔记2---组件
- 【android学习】四大组件-Content Provider
- Android学习笔记(3)————Android四大组件之三(Content Provider)
- Android学习笔记2:Android四大组件
- 学习笔记<2>Android基本四大组件
- android Content provider 组件
- Android 组件Content Provider
- android Content provider 组件
- android Content provider 组件
- android Content provider 组件
- Android学习笔记2-1--组件1--Application
- Android学习笔记2-1--组件0--Context
- Android学习笔记2-1--组件3--Reciver
- Android学习笔记2-1--组件4--Service
- Android学习笔记2-1--组件5--Activity
- Android学习笔记2-1--组件6--Fragment
- Pro Android学习笔记(一四十):List Widgets(2):App Widget Provider
- Android学习笔记2-1--组件1--Application
- Linux进程间通信——使用信号量
- centos配置jdk环境变量
- 《统计学习方法》第7章 课后题答案
- Java基础学习总结——Java对象的序列化和反序列化
- Android学习笔记2-1--组件2--Provider
- java开发类库集锦
- 多进程、多线程调试
- goEasy消息推送,pushlet 向特写用户实时推送
- IC设计基础系列之低功耗篇4:(数字IC)低功耗设计入门(四)——RTL级低功耗设计
- Android学习笔记2-1--组件3--Reciver
- 判断浏览器移动端
- 凸包 点积 Tavas and Pashmaks:CodeForces 535E
- ES6之babel