ContentProvider基础知识
1.ContentProvider入门
1.简介
- 不同程序之间的数据交换,不同app之间的数据共享
- 学会如何操作数据
- 学会如何监听数据变化
- 学会URI,URImatcher,ContentUris的如何使用
2.基本使用
- A应用,使用ContentProvider的子类进行暴漏数据(前面的五种数据存储的方式),同时给出一个Uri地址
- B应用,使用ContentReserver进行数据的接收
总之URI是数据连接的桥梁。
3.ContentProvider的简介
- 四大组件之一
- 存储和获取数据提供URI接口地址
- 可以共享数据
- 系统中常用的视频音频以及电话和短信都有相应的操作
- 使用的是非execSQL的方式执行查询
- 一种数据就是一个ContentProvider
4.ContentProvider组织数据的方式
- 以表的形式组织数据
- 联系人,通话信息,短信信息,一行就是一条记录
- _ID是唯一的
5.ContentProvider的使用
- 自定义,详见1.1.7
- 系统的
6.ContentProvider方法
抽象类,需要重写它的onCreate()、delete()、getType()、insert()、query()、update()这几个抽象方法。
- boolean onCreate(),创建后被调用,第一次访问的时候调用
- insert的用法:Uri insert(Uri uri, ContentValues values),根据Uri插入values中的数据
- query的用法:select projections from 表 where selection=selectionArgs order by sortOrder
- delete的用法:public int delete(Uri uri, String selection, String[] selectionArgs),该方法根据Uri删除where条件匹配的所有记录。
- update的用法:int update(Uri uri, ContentValues values, String selection, String[] selectionArgs),该方法根据Uri修改where条件匹配的全部记录。
- String getType(Uri uri),返回当前Uri所代表数据的MIME类型。就是一种用来定义除了基本数据类型外的其他类型的数据的一种方法
方法名称 | 功能描述 |
public boolean onCreate() | 创建ContentProvider时调用 |
public int delete(Uri uri,String selection,String[] selectionArgs) | 根据传入的Uri删除指定条件下的数据 |
public Uri insert(Uri uri,ContentValues values) | 根据传入的Uri插入数据 |
public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder) | 根据传入的Uri查询指定条件下的数据 |
public int update(Uri uri,ContentVulues values,String selection,String[] selectionArgs) | 根据传入的Uri更新指定条件下的数据 |
public String getType(Uri uri) | 用于返回指定Uri代表的MIME类型 |
注意:在增删改查方法里可以使用嵌入式SQL语句,但是就不如直接使用SQLiteDatabase的增删改查方法直接简单了。
7.ContentProvider主要方法
- 操作集合:MIME需要以vnd.android.cursor.dir/开头。
- 操作非集合:如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头。
案例1:
例如,假设一个provider含有列车时刻表,provider的authority是com.example.trains,并且它包含三个表:路线1,路线2,路线3。在URI的响应中,
content://com.example.trains/Line1。指向路线1表,provider返回对应的MIME类型为:
vnd.android.cursor.dir/vnd.example.line1
而content URI:content://com.example.trains/Line2/5。指向路线2表的第5行,provider返回的对应的MIME类型为:
vnd.android.cursor.item/vnd.example.line2
案例2:
假设一个provider有人员表,该provider的authority是cn.itcast.provider.personprovider。包含一个表:person。
例如:要得到Uri为content://cn.itcast.provider.personprovider/person指向表person,代表所有person记录,那么provider对应的MIME类型字符串应该为:“vnd.android.cursor.dir/person”。
例如:得到id为10的person记录,Uri为content://cn.itcast.provider.personprovider/person/10,那么返回的MIME类型字符串应该为:“vnd.android.cursor.item/person”。
2.自定义的ContentProvider
1.实现过程
- 数据源创建就是SQLite的帮助类和实体类等
- 自定义类ContentProvider,增删改查+getType以及onCreate方法
- 定义URI常量提供ContentResover可以访问到的ContentProvider
- 注册,privder标签
<provider
android:name=“cn.itcast.db.PersonDBProvider”
android:authorities=“cn.itcast.db.personprovider”
android:exported="true">
</provider>
<!--属性依次为:全限定类名,用于匹配的URI,是否共享数据 -->
3.系统的的ContentProvider
后续补充
4.URI
1.简介:
- 统一资源定位符,Universal Resource Identifier的简称
- 每一个ContentProvider都拥有一个公共的URI,这个URI用于表示ContentProvider提供的数据
在AndroidManifest.xml中ContentProvider提供了一个uri的authority部分作为数据的统一接口,就是android:authoritiesContentResolver通过该uri(即Content_URI)访问ContentProvider
2.URL介绍
- URL是WWW统一资源定位符,是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
- http://youke.baidu.com/course/1
3.URI组成
- 协议://URI标识(注册文件的authority定义的)/路径/ID
- 实例:
- content://com.example.codelab.transportationprovider/train:要操作train数据资源所有的记录(如train表)
- content://com.example.codelab.transportationprovider/train/10:要操作train数据资源中id为10的记录(如train表中id为10的记录)
- content://com.example.codelab.transportationprovider/train/10/name:要操作train数据资源中id为10的记录的name字段
- content://com.example.codelab.transportationprovider/train/international:要操作train表下的子表international
- content://media/external:这个Uri将返回设备上存储的所有图片;
- content://media/external/images/media/4:某个图片的Uri
- content://contacts/people:这个Uri将返回设备上的所有联系人信息;
注意:当然要操作的数据不一定来自数据库,也可以是文件等存储方式,如下:
要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
3.方法
- parse(str),将str转换成URI地址
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person/2")
Uri uri=Uri.parse("content://com.lxz.app6/studnet/2");
- List<String> getPathSegments(),获取uri的path,部分存入List
5.解析URI
1.解析URI的
- 因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。
- UriMatcher和ContentUris用于解析Uri
2.UriMatcher
- 用于匹配Uri地址,UriMatcher可以检验当前的Uri地址是不是合法的,合法才可以使用
- 检验原理:对一个URI的规则起一个编号,如果URI符合这个规则,则返回这个编号,如果在UriMatcher里找不到这个规则,则没有这个编号。规则是int值。
- 使用步骤
- 初始化UriMatcher
- 设置需要的URI规则
- 与已经注册的Uri进行匹配
3.使用UriMatcher步骤
- 初始化
UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//常量UriMatcher.NO_MATCH表示Uri不匹配时的返回码
- 设置需要匹配的Uri规则。
方法名 | 描述 |
public void addURI (String authority, String path, int code) | 添加一个用于匹配Uri的规则,当匹配成功时则给该Uri一个int值code(匹配码)。 |
public int match (Uri uri) | 与uri进行匹配 |
uriMatcher.addURI("com.lxz.app6","studnet",1);
uriMatcher.match(uri);
扩展:
sMatcher.addURI(“cn.itcast.provider.personprovider”, “person”, 1);//添加需要匹配uri(content://cn.itcast.provider.personprovider/person),如果匹配成功就会给该Uri一个匹配码1
sMatcher.addURI(“cn.itcast.provider.personprovider”, “person/#”, 2);//#号为数字通配符,用了匹配任何数字,*匹配任何字符
匹配码的值需要大于0,否则抛出IllegalArgument异常
- 使用match匹配返回匹配ma
switch (sMatcher.match(Uri.parse("content://cn.itcast.provider.personprovider/person/10"))) {
case 1:。。。。。。
break;
case 2:。。。。。。。
break;
default://不匹配
break;
}
4.ContentUris类简介
- ContentUris类用于操作Uri路径后面的ID部分。该类下的方法都为静态方法。
- 它有两个比较实用的方法:
- public static Uri withAppendedId (Uri contentUri, long id):用于为路径加上ID部分。
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")
Uri resultUri = ContentUris.withAppendedId(uri, 10);
//生成后的Uri为:content://cn.itcast.provider.personprovider/person/10
-
- public static long parseId (Uri contentUri),该方法用于从路径中获取ID
(id是指数据库中每条记录的唯一标识,即id号。)
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person/10")
long personid = ContentUris.parseId(uri);//获取的结果为:10
6.ContentResover
1.简介
- 当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成
- 获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。
- ContentResolver 类提供了与ContentProvider类相同签名的四个方法,这些方法分别会调用ContenProvider中与之对应的方法,并得到返回的结果。只管调用不管实现。这些方法的第一个参数为Uri,代表要调用的ContentProvider)
假设给定的是: Uri.parse(“content://cn.itcast.providers.personprovider/person/10”)
那么将会对uri为cn.itcast.providers.personprovider的ContentProvider进行操作,操作的数据为person表中id为10的记录。
2.使用ContentResover操作数据步骤
- 获取ContentResover,ContentResolver resolver = getContentResolver();
- 获取ContentProvider的URI标识,
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person");
- 使用ContentResolver进行增删改查操作,例如add操作
ContentValues values = new ContentValues();
values.put("name", "itcast");
values.put("age", 25);
resolver.insert(uri, values);
- 监听ContentProvider中数据的变化
- 在 android 中经常会出现改变数据库内容后再去使用数据库更新的内容,很多人会重新去 query 一遍,但是这样的问题就是程序会特别占内存,而且有可能会忘关 cursor 而导致程序内存未释放等等。
- 如果应用程序需要实时监听ContentProvider共享的数据是否发生变化,并随着ContentProvider的数据的改变而提供响应。
- CUD操作都会导致数据的变化,
getContext().getContentResolver().notifyChange(uri,null);
这行代码可用于通知所有注册在该Uri上的监听者:该ContentProvider所共享的数据发生了改变。
3.如何创建监听者,如何往Uri上加监听呢?
- 内容观察者(ContentObserver)来实现。
- 内容观察者(ContentObserver)是用来观察指定Uri所代表的数据变化,从而做一些相应的处理,类似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它。
4.创建监听的步骤
第12步“:
private final class SmsObserver extends ContentObserver{
public SmsObserver(Handler handler) {
super(handler);
}
public void onChange(boolean selfChange) {
Cursor cursor = getContentResolver().query(Uri.parse("content://sms/"),null, null, null, null);
while(cursor.moveToNext()){
StringBuilder sb = new StringBuilder(); sb.append("_id=").append(cursor.getInt(cursor.getColumnIndex("_id"))); sb.append(",address=").append(cursor.getString(cursor.getColumnIndex("address"))); sb.append(";body=").append(cursor.getString(cursor.getColumnIndex("body")));
} }}
第3步:ContentProvider通知
public class PersonContentProvider extends ContentProvider {
public Uri insert(Uri uri, ContentValues values) {
db.insert("person", "personid", values);
getContext().getContentResolver().notifyChange(uri, null);
}
}
第4步:注册监听,第三个参数就是我们创建的监听器
例:
//注册监听
getContentResolver().registerContentObserver(Uri.parse("content://sms"),
true,
//true表示只要发出通知的Uri以方法第一个参数开头都能被监听到,否则监听uri必须与发出通知的uri完全匹配才能被监听到
new PersonObserver(new Handler()));
//监听类
public class PersonObserver extends ContentObserver{
public PersonObserver(Handler handler) {
super(handler);
}
public void onChange(boolean selfChange) {
//此处可以进行相应的业务处理
}
}
5.取消注册
public final void unregisterContentObserver(ContentObserver observer)
功能:取消对给定Uri的观察