美文网首页AndroidAndroid知识Android技术知识
Android四大组件之ContentProvider

Android四大组件之ContentProvider

作者: 程序员丶星霖 | 来源:发表于2017-03-21 09:34 被阅读655次

    Android四大组件之ContentProvider

    为了在应用程序之间交换数据,Android提供了ContentProvider,它是不同应用程序之间进行数据交换的标准API,当一个应用程序需要把自己的数据暴露给其他程序使用时,该应用程序就可通过提供ContentProvider来实现;其他应用程序就可通过ContentResolver来操作ContentResolver暴露的数据。

    ContentProvider简介

    ContentProvider是不同应用程序之间进行数据交换的标准API,ContentProvider以某种Uri的形式对外提供数据,允许其他应用访问或修改数据;其他应用程序使用COntentResolver根据Uri去访问操作指定数据。

    一旦某个应用程序通过COntentProvider暴露了自己的数据操作接口,那么不管该应用程序是否启动,其他应用程序都可通过该接口来操作该应用程序的内部数据,包括增加数据、删除数据、修改数据、查询数据等。

    ContentResolver只是提供数据的访问接口,并不是像网站一样对外提供完整的页面。开发一个ContentProvider的步骤如下所示:

    1. 定义自己的ContentProvider类,该类需要继承Android提供的ContentProvider基类。
    2. 向Android系统注册ContentProvider,即在AndroidManifest.xml文件中注册这个ContentProvider,就想注册Activity一样。注册ContentProvider时需要为它绑定一个Uri。

    除此之外,自己定义的ContentProvider类还需要提供如下几个方法:

    • public boolean onCreate():该方法在ContentProvider创建后会被调用,当其他应用程序第一次访问ContentProvider时,该ContentProvider会被创建出来,并立即回调该onCreate()方法。
    • public Uri insert(Uri uri ,ContentValues values):根据该Uri插入values对应的数据。
    • public int delete(Uri uri ,String selection ,String[] selectionArgs):根据Uri删除selection条件所匹配的全部记录。
    • public int update(Uri uri ,ContentValues values ,String selection ,String[] selectionArgs):根据Uri修改selection条件所匹配的全部记录。
    • public Cursor query(Uri uri ,String[] projection ,String selectionn ,String[] selectionArgs ,String sortOrder):根据Uri查询出selection条件所匹配的全部记录,其中projection就是一个列名列表,表明只选择出指定的数据列。
    • public String getType(Uri uri):该方法用于返回当前Uri所代表的数据的MIME类型。如果该Uri对应的数据可能包括多条记录,那么MIME类型字符串应该以vnd.android.cursor.dir/开头;如果该Uri对应的数据只包含一条记录,那么MIME类型字符串应该以vnd.android.cursor.item/开头。

    Uri简介

    ContentProvider要求的Uri与互联网的URL类似,例如如下Uri:

    content://org.crazyit.providers.dictprovider/words
    

    它可以分为如下三部分:

    • content://:这个部分是Android的ContentProvider规定的,就像是上网的协议默认是http://一样。暴露ContentProvider、访问ContentProvider的协议默认是content://。
    • org.crazyit.providers.dictprovider:这个部分就是COntentProvider的authorities。系统就是由这个部分来找到操作哪个ContentProvider的。只要访问指定的ContentProvider,这个部分就是固定的,
    • words:资源部分(或者说数据部分)。当访问者需要访问不同资源时,这个部分是动态改变的。

    为了将一个字符串转换成Uri,Uri工具类提供了parse()静态方法。例如,如下代码即可将 字符串转换为Uri:

    Uri  uri = Uri.parse("content://org.crazyit.providers.dictprovider/word/2")
    

    ContentResolver操作数据

    ContentProvider的作用是暴露可供操作的数据;其他应用程序则通过ContentProvider来操作ContentProvider所暴露的数据,ContentResolver相当于HttpClient。
    Context提供了如下方法来获取ContentResolver对象:

    • getContentResolver():获取该应用默认的ContentResolver对象。

    一旦在程序中获得了ContentResolver对象之后,接下来就可调用ContentResolver的如下方法来操作数据了。

    • insert(Uri uri ,ContentValues values):向Uri对应的ContentProvider中插入values对应的数据。
    • delete(Uri uri ,String where ,String[] selectionArgs):删除Uri对应的ContentProvider中where提交匹配的数据。
    • update(Uri uri ,ContentValues values ,String where ,String[] selectionArgs):更新Uri对应的ContentProvider中where提交匹配的数据。
    • query(Uri uri ,String[] projection ,STring selection ,String[] selectionArgs ,String sortOrder):查询Uri对应的ContentProvider中where提交匹配的数据。

    一般来说,ContentProvider是单实例模式的,当多个应用程序通过ContentResolver来操作ContentProvider提供的数据时,ContentResolver调用的数据操作将会委托给同一个ContentProvider处理。

    ContentProvider与ContentResolver的关系

    从ContentResolver、ContentProvider和Uri的关系来看,无论是ContentResolver,还是ContentProvider,它们所提供的增删改查方法的第一个参数都是Uri。也就是说,Uri是ContentProvider和ContentResolver进行数据交换的标识。ContentResolver对指定Uri执行增删改查的数据操作,但Uri并不是真正的数据中心,因此这些增删改查操作会委托给该Uri对应的ContentProvider来实现。

    ContentProvider、Uri、ContentResolver三者之间的关系如下图所示:

    0.jpg

    以指定Uri为标识,ContentResolver可以实现“间接调用”ContentProvider的增删改查方法:

    1. 当A应用调用ContentResolver的insert()方法时,实际上相当于调用了该Uri对应的ContentProvider的insert()方法。
    2. 当A应用调用ContentResolver的update()方法时,实际上相当于调用了该Uri对应的ContentProvider的update()方法。
    3. 当A应用调用ContentResolver的delete()方法时,实际上相当于调用了该Uri对应的ContentProvider的delete()方法。
    4. 当A应用调用ContentResolver的query()方法时,实际上相当于调用了该Uri对应的ContentProvider的query()方法。

    开发ContentProvider子类

    开发ContentProvider只要如下两步:

    1. 开发一个ContentProvider子类,该子类需要实现query()、insert()、update()和delete()等方法。
    2. 在AndroidManifest.xml文件中注册该ContentProvider,指定android:authorities属性。

    配置ContentProvider

    只要为<applicaton.../>元素添加了<provider.../>子元素即可配置ContentProvider。例如如下的配置片段:

    <provider
            android:name=".FirstProvider"
            android:authorities="org.crazyit.providers.firstprovider"
            android:exported="true"/>
    

    配置ContentProvider时通常指定如下属性:

    • name:指定该ContentProvider的实现类的类名。
    • authorities:指定该ContentProvider对应的Uri(相当于为该ContentProvider分配一个域名。)
    • android:exported:指定该ContentProvider是否允许其他应用调用。如果将该属性设为false,那么该ContentProvider将不允许其他应用调用。

    为了确定ContentProvider实际能处理的Uri,以及确定每个方法中Uri参数所操作的数据,Android系统提供了UriMatcher工具类,主要提供了如下两个方法:

    • void addURI(String authority ,String path ,int code):该方法用于向UriMatcher对象注册Uri。其中authority和path组合成一个Uri,而code则代表该Uri对应的标识码。
    • int match(Uri uri):根据前面注册的Uri来判断指定Uri对应的标识码。如果找不到匹配的标识码,就会返回-1。

    Android还提供了一个ContentUris工具类,它是一个操作Uri字符串的工具类,提供了如下两个工具方法:

    • withAppendedId(uri , id):用于为路径加上ID部分。
    • parseId(uri):用于从指定Uri中解析出所包含的ID值。

    操作系统的ContentProvider

    Android系统本身提供了大量的ContentProvider,使用ContentResolver操作系统的ContentProvider数据的步骤也是两步:

    1. 调用Context的getContentResolver()获取ContentResolver对象;
    2. 根据需要调用ContentResolver的insert()、delete()、update()和query()方法操作数据。

    Android系统用于管理联系人的ContentProvider的几个Uri如下:

    • ContactsContract.Contacts.CONTENT_URI:管理联系人的Uri。
    • ContactsContract.CommonDataKinds.Phone.CONTENT_URI:管理联系人的电话的Uri。
    • ContactsContract.CommonDataKinds.Email.CONTENT_URI:管理联系人的E-mail的Uri。

    Android为多媒体提供的ContentProvider的Uri如下所示:

    • MediaStore.Audio.Media.EXTERNAL_CONTENT_URI:存储在外部存储其上的音频文件内容的ContentProvider的Uri。
    • MediaStore.Audio.Media.INTERNAL_CONTENT_URI:存储在手机内部存储器上的音频文件内容的ContentProvider的Uri。
    • MediaStore.Images.Media.EXTERNAL_CONTENT_URI:存储在外部存储器上的图片文件内容的ContentProvider的Uri。
    • MediaStore.Images.Audio.Media.INTERNAL_CONTENT_URI:存储在手机内部存储器上的图片文件内容的ContentProvider的Uri。
    • MediaStore.Video.Media.EXTERNAL_CONTENT_URI:存储在外部存储器上的视频文件内容的ContentProvider的Uri。
    • MediaStore.Video.Audio.Media.INTERNAL_CONTENT_URI:存储在手机内部存储器上的视频文件内容的ContentProvider的Uri。

    监听ContentProvider的数据改变

    在之前的介绍中,只要导致了ContentProvider数据发生了改变,程序中就调用如下代码:

    getContext().getContentResolver(),notifyChange(uri ,null);
    

    为了在应用程序中监听ContentProvider数据的改变,需要利用Android提供的ContentObserver基类。监听ContentProvider数据改变的监听器需要继承ContentObserver类,并重写该基类所定义的onChange(boolean selfChange)方法--当所监听的ContentProvider数据发生改变时,该onChange()方法将会被触发。

    为了监听指定ContentProvider的数据变化,需要通过ContentResolver向指定Uri注册ContentObserver监听器。ContentResolver提供了如下方法来注册监听器:

    • registerContentObserver(Uri uri , boolean notifyForDescendents , ContentObserver observer)

    这个方法的三个参数分别表示:

    • uri:该监听器所监听的ContentProvider的Uri。
    • notifyForDescendents:如果该参数设为true,假如注册监听的Uri为content://abc,nameUri为contetn://abc/xyzcontent://abc/xyz/foo的数据改变时也会触发该监听器;如果设为false,那么只有content://abc的数据发生改变时才会触发该监听器。
    • observer:监听器实例。

    提供程序访问的替代形式

    提供程序访问的三种替代形式在应用开发的过程中十分重要:

    • 批量访问:可以通过ContentProviderOperation类中的方法创建一批访问调用,然后通过ContentResolver.applyBatch()执行它们。
    • 异步查询:应该在单独线程中执行查询。
    • 通过Intent访问数据:尽管无法直接向提供程序发送Intent,但是可以向提供程序的应用发送Intent,后者通常具有修改提供程序数据的最佳配置。

    好的,ContentProvider就介绍这些吧!!欢迎关注我的微信公众号!

    我的微信公众号.jpg

    相关文章

      网友评论

      本文标题:Android四大组件之ContentProvider

      本文链接:https://www.haomeiwen.com/subject/ohsinttx.html