(6)内容提供者和内容观察者

6.1内容提供者概述

在Android中应用程序之间是相互独立的,分别运行在自己的进程中,如果需要应用程序之间共享数据,则需要用到ContentProvioder,这个组件时Android四大组件之一,其功能时在Android不同程序之间实现数据的共享,不仅允许一个程序访问另一个程序的数据,还可以选择只共享哪一部分的数据,保证隐私数据不被泄露

  • A程序需要使用ContentProvider暴露数据,该数据才能够被其他应用程序操作,B程序通过ContentResolver操作A程序暴露出来的数据,A程序将操作的结果返回给ContentResolver,然后ContentResolver再将操作的结果返回给B程序,对于ContentResolver来说最重要的就是数据模型(Data Model)和Uri
数据模型

ContentResolver使用基于数据库模型的简单表格来提供需要共享的数据,每一行表示一条数据,每一列代表特点类型和含义的数据,并且每一条数据都包含一个名为_ID的字段标识每一条数据

_IDNAMENUMBEREMAIL
1xxx164****5656123@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创建内容提供者

  1. 创建一个继承抽象类ContentResolver的类
  2. 重写其中的方法
//创建一个新类继承抽象类
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则默认通知上一步注册的内容观察者

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值