ym——Android从零开始(9)(ContentProvider内容提供者)(新)

ym——Android从零开始(9)(ContentProvider内容提供者)(新)ContentProvider内容提供者ContentProvider 进程间通讯,进程间数据的访问/对外共享数据用优点:提供了统一的访问方式原理分析图实现抽象类ContentProvider  安卓应用实现抽象类ContentProvider,并实现对本地数据库增删查改的四个方法,且在清单文件注册该ContentProvid

大家好,又见面了,我是你们的朋友全栈君。

转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持!


前言

学习完了多种数据存储方法,接下来我们来学习,如果进程间共享数据


ContentProvider内容提供者

ContentProvider 进程间通讯,进程间数据的访问/对外共享数据用

优点:提供了统一的访问方式

原理分析图:

图片1.png

图片2.png


实现抽象类ContentProvider

Android应用实现抽象类ContentProvider,并实现对本地数据库增删查改的四个方法,且在清单文件注册该ContentProvider。就如同给其他应用提供了一个读取本地数据的接口。

public class PersonProvider extends ContentProvider {private DBhelp dbOpenHelper;//UriMatcher类//addURI(authority, path, code);注册Uri,指定code//match(uri);匹配Uri,如果有返回code,无返回-1.//UriMatcher 其实是一个arrayList集合        private static final UriMatcher MATCHER = new UriMatcher(                        UriMatcher.NO_MATCH);// 判断Uri        private static final int PERSONS = 1;        private static final int PERSON = 2;        static {                // (主机名,路径部分,匹配码);                // 添加进了要等待的匹配的路径                MATCHER.addURI("com.cym.provides.PersonProvider", "person", PERSONS);                MATCHER.addURI("com.cym.provides.PersonProvider", "person/#", PERSON); // #                                                                                                                                                                // 代表数字                                                                                                                                                                // *                                                                                                                                                                // 代表所有字符        }@Override        public boolean onCreate() {// 这个方法不是由程序员调用的而是由系统调用的,当这个程序启动被创建出来后这个方法自动调用,所以它只会被调用一次,适于做数据初始化操作。         ContentProvider在启动应用程序的时候创建。防止并发状态,当android应用程序安装的时候,会在注册表里面把应用程序所有的信息进行注册。所有在开机之后,系统里面所有的contentProvider都会被创建出来        dbOpenHelper = new DBhelp(getContext());                return false;        }        // 我们还需要判断URI 这样就能够知道外部应用操作的处理方式        // 以下方法都是提供给外部应用操作query,insert,delete,update//Uri  与  ContentUri//ContentUris.parseId(uri);得到当前uri的资源id://Uri.parse(“conten://authority/path”);将字符串解析成Uri对象// ContentUris.withAppendedId(uri, id);给当前uri添加id,并且返回新的uri:        @Override        public Cursor query(Uri uri, String[] projection, String selection,                        String[] selectionArgs, String sortOrder) {SQLiteDatabase db = dbOpenHelper.getWritableDatabase();                Cursor cursor = null;                switch (MATCHER.match(uri)) {                case PERSONS:                        cursor = db.query("person", projection, selection, selectionArgs,                                        null, null, sortOrder);                        break;                case PERSON://得到当前uri的资源id:                        long rowid = ContentUris.parseId(uri);                        String where = "_id=" + rowid;                        if (selection != null && !"".equals(selection.trim())) {                                where += " and " + selection;                        }                        cursor = db.query("person", projection, where, selectionArgs, null,                                        null, sortOrder);                        break;                default:                        throw new IllegalArgumentException("this is Unknown Uri:" + uri);                }                return cursor;               }        // 返回操作的内容文件        @Override        public String getType(Uri uri) {                switch (MATCHER.match(uri)) {                case PERSONS:                         return "vnd.android.cursor.dir/person";                case PERSON:                         return "vnd.android.cursor.item/person";                default:                        throw new IllegalArgumentException("this is Unknown Uri:" + uri);                }        }        @Override        public Uri insert(Uri uri, ContentValues values) {                SQLiteDatabase db = dbOpenHelper.getWritableDatabase();                switch (MATCHER.match(uri)) {                case PERSONS:                        long rowid = db.insert("person", "name", values);// 等于你的主键值                        // content://com.cym.provides.personprovider/person/10                        // Uri insertUri =                        // Uri.parse("content://com.cym.provides.personprovider/person/"+rowid);                        // 两种方法                        Uri insertUri = ContentUris.withAppendedId(uri, rowid);                        //通过上下文拿到contentResolver                                Context context = getContext();                                ContentResolver cr = context.getContentResolver();                                //调用该方法时 通知监听                                cr.notifyChange(uri, null);                        return insertUri;                default:                        throw new IllegalArgumentException("this is Unknown Uri:" + uri);                }                }        }        @Override        public int delete(Uri uri, String selection, String[] selectionArgs) {                       }        @Override        public int update(Uri uri, ContentValues values, String selection,                               }}

清单文件注册

安卓应用提供给其他应用操作本地数据的接口,必须在清单文件注册。

在application标签内部添加provider标签

<providerandroid:name=".PersonProvider"android:authorities="com.cym.provides.PersonProvider"/>

Name参数表示Provider的位置。. 代表在此包底下

Authorities参数表示域名类似于www.hao123.com (必须唯一:本地唯一)

虽然没有规定Authorities的书写规范,但是我们一般使用PersonProvider的全名

例:com.cym.provides.PersonProvider


其他应用访问

为什么使用uri

保证数据的安全性不让所有的数据对外暴露,所以我们可以指定只有那些uri可以被被人访问,所以db中放入一组uri集合

其他应用通过Context.getContentResolver()得到ContentResolver对象,根据指定的Uri可以调用ContentProvider对应的增删查改方法对数据库进行操作。

客户端的ContentResolver对象要想调用服务端ContentProvider对象的响应的方法,也必须通过该ContentProvider对应的Uri找到ContentProvider,才能实现调用。

Uri代表了要操作的数据,Uri主要包含了两部分信息:1》需要操作的ContentProvider 2》对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:

图片3.png

ContentProvider(内容提供者)的scheme已经由Android所规定, scheme为:content://

主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。

路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:

要操作person表中id10的记录,可以构建这样的路径:/person/10

要操作person表中id10的记录的name字段, person/10/name

要操作person表中的所有记录,可以构建这样的路径:/person

要操作xxx表中的记录,可以构建这样的路径:/xxx

当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:

要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name

如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:

Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")//生成指向Server端CP的Uri实例对象//得到域名        uri=Uri.parse("content://com.huaao.ContentProvider");//拿到resovlerContentResolver cr= this.getContext().getContentResolver();        //调用ContentResolver对象的query()方法。传入域名        cr.query(uri, null, null, null, null);//客户端代码.delete.setOnClickListener(new OnClickListener() {        public void onClick(View v) {                                //指定资源id        uri=Uri.parse("content://com.huaao.ContentProvider/student/2");        //调用CR的delete()方法        cr.delete(url, null, null);        }});

监听数据更改

图片4.png


ContentObserver

安卓提供ContentObserver实现数据变化后监听

监听三步骤:

1,实现抽象类 ContentObserver,重写onChange()方法

2,调用ContentProvider注册ContentObserver

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ContentResolver cr = getContentResolver();
        Uri uri = Uri.parse("content://com.cym.provides.PersonProvider/person");
        Cursor query = cr.query(uri, null, null, null, null);
        while (query.moveToNext()) {
               
            Log.i(TAG, query.getString(query.getColumnIndex("name")));
                }
        Log.i(TAG, "第一次数据查询完了");
        ContentObserver observer = new MyContentObserver(new Handler());
        //注册监听
        cr.registerContentObserver(uri, true, observer);
}
//实现抽象类 ContentObserver,
   private class MyContentObserver extends ContentObserver{
                public MyContentObserver(Handler handler) {
                        super(handler);
                        // TODO Auto-generated constructor stub
                }
                @Override
//重写onchenge
                public void onChange(boolean selfChange) {
                 
                        super.onChange(selfChange);
                         ContentResolver cr = getContentResolver();
                         Uri uri = Uri.parse("content://com.cym.provides.PersonProvider/person");
                        Cursor query = cr.query(uri, null, null, null, null);
                        while (query.moveToNext()) {
                               
                            Log.i(TAG, query.getString(query.getColumnIndex("name")));
                                }
                        Log.i(TAG, "第二次次数据查询完了");
                       
                }
    }
registerContentObserver(uri,是否连带子Uri,Observer对象);

3, 当数据发生变化,提醒监听者

notifyChange(uri, Observer);

在你要监听的方法里写入notifyChange(uri, Observer);

例子:

public Uri insert(Uri uri, ContentValues values) {                SQLiteDatabase db = dbOpenHelper.getWritableDatabase();                switch (MATCHER.match(uri)) {                case PERSONS:                        long rowid = db.insert("person", "name", values);// 等于你的主键值                        // content://com.cym.provides.personprovider/person/10                        // Uri insertUri =                        // Uri.parse("content://com.cym.provides.personprovider/person/"+rowid);                        // 两种方法                        Uri insertUri = ContentUris.withAppendedId(uri, rowid);                        //通过上下文拿到contentResolver                                Context context = getContext();                                ContentResolver cr = context.getContentResolver();                                //调用该方法时 通知监听                                cr.notifyChange(uri, null);                        return insertUri;                default:                        throw new IllegalArgumentException("this is Unknown Uri:" + uri);                }        }

最后结果流程就是  第一个次查询数据完成之后,我们在给查询这个应用注册了监听并且重写onChange()方法,以及我们在insert方法里面写了通知监听如果有其他应用访问insert方法,就会触发监听同志,就会执行注册监听时的onChange()方法。


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/150586.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • C++ 重制植物大战僵尸(Cocos2dx开源项目)

    此游戏全部由本人自己制作完成。游戏大部分的素材来源于原版游戏素材,少部分搜集于网络,以及自己制作。此游戏为同人游戏而且仅供学习交流使用,任何人未经授权,不得对本游戏进行更改、盗用等,否则后果自负。目前有六种僵尸和六种植物,植物和僵尸的动画都是本人做的。qq:2117610943最新视频–>点击观看开源代码下载提取码:3vzm点击下载–>11月28日新增…

  • 自动化测试平台(三):用户token验证及用户增删改查接口开发

    自动化测试平台(三):用户token验证及用户增删改查接口开发上一篇我们实现了用户登录的验证并返回token。那如何去校验请求的token是否有效呢?这篇内容为你讲解token的验证及用户管理(增删改查)的功能。

  • Microsoft Visio Pro 2016产品密钥激活成功教程完整免费下载

    Microsoft Visio Pro 2016产品密钥激活成功教程完整免费下载https://blog.csdn.net/jingxiansheng/article/details/75805699

  • tensorflow2.2_实现Resnet34_花的识别[通俗易懂]

    tensorflow2.2_实现Resnet34_花的识别[通俗易懂]残差块    Resnet是由许多残差块组成的,而残差块可以解决网络越深,效果越差的问题。    残差块的结构如下图所示。其中:weightlayer表示卷积层,用于特征提取。F(x)F(x)F(x)表示经过两层卷积得到的结果。xxx表示恒等映射。F(x)+xF(x)+xF(x)+x表示经过两层卷积后与之前的卷积层进行结合。所以F(x)F(x)F(x)和xxx代表的是相同的信号。作用:将浅层网络的信号递给深层网络,使网络得到更好的结果。批量归一化(BatchNormaliz

  • 通俗易懂讲解均方误差 (MSE)「建议收藏」

    通俗易懂讲解均方误差 (MSE)「建议收藏」测量预测值与某些真实值匹配程度。MSE通常用作回归问题的损失函数。例如,根据其属性估算公寓的价格。这是维基百科中定义的均方误差(MSE)公式。它代表了一个非常简单的概念,但如果您刚开始使用ML,可能不太容易读懂。让我们从内而外拆开包装。MSE计算模型的预测Ŷ与真实标签Y的接近程度。您希望误差变为0。如果您预测房价,误差可能是预测价格与实际价格之间的差异。从标签中减去预测是行不通的。误差可能为负也可能为正,这是对样本求和时的问题。您可以取绝对值或误差的平方。取平方有一个特性,它惩罚更大的

  • python做语音信号处理

    python做语音信号处理作者:凌逆战时间:2019年11月1日博客园地址:https://www.cnblogs.com/LXP-Never/p/10078200.html音频信号的读写、播放及录音标准的python已经支持WAV格式的书写,而实时的声音输入输出需要安装pyAudiio(http://people.csail.mit.edu/hubert/pyaudio)。最后我们还将使用pyMedia(…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号