文章目录
6.1内容提供者概述
在Android中应用程序之间是相互独立的,分别运行在自己的进程中,如果需要应用程序之间共享数据,则需要用到ContentProvioder,这个组件时Android四大组件之一,其功能时在Android不同程序之间实现数据的共享,不仅允许一个程序访问另一个程序的数据,还可以选择只共享哪一部分的数据,保证隐私数据不被泄露
- A程序需要使用ContentProvider暴露数据,该数据才能够被其他应用程序操作,B程序通过ContentResolver操作A程序暴露出来的数据,A程序将操作的结果返回给ContentResolver,然后ContentResolver再将操作的结果返回给B程序,对于ContentResolver来说最重要的就是数据模型(Data Model)和Uri
数据模型
ContentResolver使用基于数据库模型的简单表格来提供需要共享的数据,每一行表示一条数据,每一列代表特点类型和含义的数据,并且每一条数据都包含一个名为_ID的字段标识每一条数据
_ID | NAME | NUMBER | |
---|---|---|---|
1 | xxx | 164****5656 | 123@qq.com |
如果要查询上述表的任何一个字段,则需要知道各个字段对应的数据类型,Cursor对象专门为这些数据类型提供了相关的方法,getInt()
,getString()
,getLong()
等
Uri
ContentResolver与SQLiteDatabase类似,提供一系列增删改查的方法对数据进行操作,但是不同于数据库,这里的增删改查以Uri的形式对外提供数据,Uri为ContentResolver中的数据建立了唯一的标识符,该标识主要用来区分不同的与应用程序,一般为了authority产生冲突,会直接采用应用程序的包名直接进行命名,Uri由三部分组成
Uri:content://package/person
- content:scheme,Android规定的标准前缀
- package:authority,唯一标识
- person:path,标识要访问的数据
6.2创建内容提供者
- 创建一个继承抽象类ContentResolver的类
- 重写其中的方法
//创建一个新类继承抽象类
class Mycontentprovider extends ContentProvider//继承抽象类
{
@Override
public boolean onCreate() {//创建内容提供者的时候自动调用
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {//查
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {//获得MIME类型的数据
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {//增
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {//删
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {//改
return 0;
}
}
AndroidManifest.xml
<provider
android:authorities="cn.itcast.testandroid.Mycontentprovider"
android:name=".MyContentProvider"
android:enabled="true"
android:exported="true">
</provider>
上述代码中各个属性的意思
- name:MyContenProvider的全称,可以用.MyContenProvider代替
- authorities:标识了MyContenProvider提供的数据,该值可以是一个或者多个URI authority,多个authority可以用逗号隔开
- enabled:表示MyContenProvider能否被系统实例化,如果属性时true则表示可以被系统实例化,false则不允许被系统实例化,该属性的默认值是true
- exported:表示MyContenProvider可以被其他应用程序使用,如果这个属性的值为true则表示任何应用程序都可以通过Uri访问MyContenProvider,反正则表示用户id(程序build.gradle文件中的applicationId)相同的应用程序才能够访问到他
6.3访问其他应用程序
6.3.1查询其他程序的数据
ContentResolver充当一个中介的角色,其暴露数据的时候提供了相应的Uri,所以要访问现有的ContentProvider时要指定Uri,然后通过ContentResolver来对数据采取操作,具体步骤如下
1 通过parse()方法解析Uri
Uri uri = Uri.parse("content://cn.itcast.mycontentprovider/person");
2 通过query()方法查询数据
ContentResolver resolver = context.getContentResolver();
Cursor cursor = resolver.query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder);
上述query传递的五个参数如下
- uri:表示查询其他应用程序数据需要的Uri
- projection:表示要查询的内容,该内容相当于数据库中每列的内容
- selection:表示设置的查询条件,相当于sql语句中的where
- selectionArgs:该参数需要配合section使用,如果section语句中有了?,则sectionArgs会替换掉?,否则参数sectionArgs传递的值是null
- sortOrder:表示查询的数据按照什么顺序进行排序,相当于sql语句中的Order by,如果该参数传递的值是null,则数据默认是按照升序排列,如果想要数据降序排序,则该参数传递的值是字符串
" DESC"
,注意这里DESC之前有一个空格
3 通过while()循环语句遍历查询到的数据
举例:(与前面数据库类似)
while(cursor.moveToNext()) {
String address = cursor.getString(0);
long date = cursor.getLong(1);
int type = cursor.getInt(2);
}
cursor.close();
UriMatcher类
如果一个ContentProvider含有多个数据源(有多张表格),则可以使用UriMatcher类对Uri进行匹配
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);//初始化
matcher.addURI("cn.itcast.contentprovider","people",PEOPLE);//注册需要的Uri
matcher.addURI("cn.itcast.contentprovider","person/#",PEOPLE_ID);
Uri uri = Uri.parse("content://"+"cn.itcast.contentprovider"+"/people");
int match = matcher.match(uri);//匹配操作
switch (match) {
case PEOPLE:
break;
case PEOPLE_ID:
break;
}
6.4 内容观察者
ContentPesolver可以查询到ContentProvider共享出来的数据,如果应用程序要实时监听ContentResolver的数据是否发生变化,则需要使用内容观察者
6.4.1 什么是内容观察者
内容观察者用于观察指定Uri代表的数据的变化,数据变化的时候就会触发ContentObserver的onChange()方法,此时在Onchange中使用ContentResovler就可以查询到变化的数据
创建内容观察者
继承ContentObserve类,重写父类的OnChange方法和构造方法
class MyObserver extends ContentObserver {
public MyObserver(Handler handler) {
super(handler);
}
public void onChange(boolean selfChange) {
super.onChange(selfChange);
}
}
上述构造方法中的Handler参数可以是主线程中的Handle对象,也可以是别的对象中的Handle对象
注册内容观察者
ContentResolver resolver = getContentResolver();//获取ContentResolver对象
Uri uri = Uri.parse("content://aaa.bbb.ccc");//获取Uri
resolver.registerContentObserver(uri,true,new MyObserver(new Handler()));//注册内容观察者
最后一行当第二参数的值为true 的时候可以匹配Uri派生的其他Uri,为false的时候就只匹配当前的Uri,第三个参数代表匹配的内容观察者
取消注册内容观察者
@Override
protected void onDestroy() {
super.onDestroy();
getContentResolver().unregisterContentObserver(new MyObserver(new Handler()));//取消
}
注意:在内容监听者监听的ContentProvider中,重写insert(),delete(),update()方法的时候,程序都会调用如下代码,提示ContentProvider共享的数据发生了变化
getContext().getContentResolver().notifyChange(uri,null);
第二个参数代表内容观察者,参数为null则默认通知上一步注册的内容观察者