当前位置 博文首页 > 启舰:ContentProvider数据库共享之——概述

    启舰:ContentProvider数据库共享之——概述

    作者:[db:作者] 时间:2021-08-07 22:06

    前言:项目终于结束了,终于有自己的时间了,感觉几个月没什么进展了,毕业的时间越长,反而觉得学到的知识越少。努力吧。

    ?

    相关文章:
    1、《ContentProvider数据库共享之——概述》
    2、《ContentProvider数据库共享之——实例讲解》
    3、《ContentProvider数据库共享之——MIME类型与getType()》
    4、《ContentProvider数据库共享之——读写权限与数据监听》


    这篇主要给大家全局性的讲讲应用间的数据库共享。我们都知道每个应用的数据库都只允许创建它的应用自己来读写,那其它应用要访问这个数据库要怎么办呢;这就是数据库共享。

    举个例子:如果有写了两个姊妹应用,比如,阿里旺旺和淘宝;如果我想在用淘宝的时候就直接想看到旺旺里跟哪个卖家的聊天记录怎么办(不考虑网络获取,只考虑本地共享),这时候我就要去旺旺的数据库里去找了吧。这就是两应用间的数据库共享问题。而ContentProvider就是解决这个问题的。下面就从ContentProvider设计者的角度来讲讲这两个不同应用间数据库共享问题。

    一、两应用间如何通信

    ?

    首先,我们最先想到的方法应该是如下面这张图这样的,自身应用写好各个数据库接口,供其它应用调用

    ?

    那么,问题来了,首先,其它应用如何调起这个应用的数据库接口;要知道你要调这个接口的应用很可能根本就没有运行。

    咦,好像有一种方法就能调起没有运行的应用——隐式Intent!!!

    隐式Intent的调用方法如下,如果这个Activity要供其它应用调用,那么这个Activity在这个应用AndroidManifest.xml中声明方式为:

    ?

            <activity
                android:name=".SecondActivity"
                android:label="@string/title_activity_second" >
                <intent-filter>
                    <action android:name="harvic.test.qijian"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                </intent-filter>
            </activity>

    在其它APP中,要调这个Activity时,就使用:

    ?

    Intent intent = new Intent("harvic.test.qijian");
    startActivity(intent);

    我们先分析一下隐式Intent是如何做到的。

    ?

    1、首先,我们将filter信息写在了AndroidManifest.xml中;

    2、当有一个隐式Intent要匹配时,系统(注意是系统!)会搜索整个手机上所有APP的Acitivity进行匹配,如果有匹配的并且有使用权限的,就起起来;大家想想当你在应用中点击网址链接的时候,是不是会转到浏览器中,这就是用的隐式Intent匹配。如果你手机上有多个应用可以匹配,那么就会以列表的形式列出来供你选择开哪一个。具体有关隐式Intent的内容,可以参看《Intent详解一》和《Intent详解二》

    根据隐式Intent,我们是不是有受到启发,那我们也可额外再开出来一个东东,仿照隐式Intent的方式来进行全局匹配,如果匹配成功就执行操作!!!对,这就是那帮谷歌老头的设计方法,他们设计的东东就是ContentProvider的URI!!

    ?

    ?

    ?

    二、ContentProvider与对应的URI

    ContentProvider的URI就是下面这个形式的:

    主要分三个部分:scheme, authority and path。scheme表示上图中的content://,authority表示B部分,path表示C和D部分。
    A部分:表示是一个Android内容URI,说明由ContentProvider控制数据,该部分是固定形式,不可更改的。
    B部分:是URI的授权部分,是唯一标识符,用来定位ContentProvider。格式一般是自定义ContentProvider类的完全限定名称,注册时需要用到,如:com.example.transportationprovider
    C部分和D部分:是每个ContentProvider内部的路径部分,C和D部分称为路径片段,C部分指向一个对象集合,一般用表的名字,如:/trains表示一个笔记集合;D部分指向特定的记录,如:/trains/122表示id为122的单条记录,如果没有指定D部分,则返回全部记录。

    这个URI就是用来进行全局匹配的,那AndroidManifest.xml里又要怎么写呢?

    再回想下隐式Intent,在隐式Intent中,Intent-fliter是Activity的一部分,专门过滤隐式Intent的匹配请求的,如果Intent-fliter匹配后,就启动对应的Activity;

    那我们也可以设计一个东东,把这个URI作为它的一部分,当匹配成功以后,就进这个东东里操作数据库。这个东东就是ContentProvider;

    ContentProvider在AndroidManifest.xml中的声明方式为:(与上面的URI对应)

            <provider
                android:name=".NoteContentProvider"
                android:authorities="com.example.transportationprovider"
                android:exported="true"/>

    这里的android:authorities必须与上面URI中的B部分一样,因为这个就是用来全局匹配的authority!!!!只有URI的authority与provider的android:authorities匹配上了,才会进入后面的操作

    到这里,我也要祭出大招了:ContentURI的全局流程图

    上面,我们说到了第一步和第二步,当匹配成功ContentProvider以后,就开始进入我们指定的ContentProvider进行处理;大家估计也注意到了,我们的ContentURI的完整部分为:content://com.example.transportionprovider/trains/122

    到第二步,我们已经匹配到了content://com.example.transportionprovider,那后面的/trains/122的匹配工作就只有交由ContentProvider来处理了。

    在ContentProvder中的匹配是利用UriMatcher来完成的!

    三、UriMatcher

    UriMatcher的匹配工作的第一步就是先将所需要的匹配的URI使用addURI()添加到UriMatcher中,

    public void addURI(String authority, String path, int code)

    其中第一个参数authority:就是URI对应的authority

    path:就是我们在URI中?authority后的那一串

    code:表示匹配成功以后的返回值;

    下面以我们的URI=content://com.example.transportionprovider/trains/122来演示一下

        public static final String AUTHORITY = "com.alexzhou.provider.NoteProvider";
        private static final UriMatcher sUriMatcher;
        static {
            sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
            sUriMatcher.addURI(AUTHORITY, "trains", 1);
            sUriMatcher.addURI(AUTHORITY, "trains/#", 2);
        }

    上段代码中:

    ?sUriMatcher.addURI(AUTHORITY, "trains", 1);

    表示匹配content://com.example.transportionprovider/trains,如果匹配成功返回1

    ?sUriMatcher.addURI(AUTHORITY, "trains/#", 2);

    其中

    #表示匹配任意数据ID

    *表示匹配任意文本

    所以这句的意思就是匹配content://com.example.transportionprovider/trains/任意数字ID ?比如我们的content://com.example.transportionprovider/trains/122

    在匹配以后就是响应请求啦。至于如何响应请求就在下节在讲了,这节就主要把流程给大家讲清楚及涉及到有知识,到这,整体流程就讲完了,但还有个地方还没说,就是第三方应用如何根据URI来指定操作的,是哪个函数来操作URI的呢?

    它就是ContentResolver;

    下面简单先说一下ContentResolver的函数:

    插入(insert):

             String CONTENT_URI = content://com.example.transportionprovider/trains/122;
            ContentResolver cr =getContentResolver();
            ContentValues values = new ContentValues();
            values.put("title", "hello");//数据库的键值对
            values.put("content", "my name is harvic");
    
            Uri uri = cr.insert(CONTENT_URI, values);

    ?

    在第三方中,我们要向指定应用的数据库中插入一条记录,其中title字段的值为hello,content字段的值为my name is harvic。就是用上面的这一段代码,有没有很简单

    这段代码一调用,那可就吊了,系统会搜索手机上所有APP的AndroidManifest.xml,看哪个provider的authority匹配,在匹配之后,转到对应的类中,再让UriMatcher匹配后面的PATH字段,都完全匹配之后,就执行ContentProvider中的insert方法!!!!这就是是整个流程。

    当然ContentResolver除了insert方法还有query()、update()、delete()方法,可以执行第三方数据库的任何操作。

    ?

    好了,到这整个流程就讲完,想必大家对ContentProvider涉及到的几部分也都清楚了吧。下篇给大家用实例讲讲,他们是如何工作的。

    ?

    请大家尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/44521461?谢谢!

    ?

    如果你喜欢我的文章,你可能更喜欢我的公众号

    启舰杂谈

    ?

    ?

    cs
    下一篇:没有了