原文链接:http://www.orlion.ga/612/

内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访数据的安全性。目前,使用内容提供器是 Android实现跨程序共享数据的标准方式。内容提供器的用法一般有两种, 一种是使用现有的内容提供器来读取和操作相应程序中的数据,另一种是创建自己的内容提供器给我们程序的数据提供外部访问接口。

一、访问其他程序中的数据

Android自带的电话薄、短信、媒体库等程序提供了外部访问接口,第三方程序可以利用这些数据进行开发

1、ContentResolver的基本用法

如果想要访问内容提供器的数据需要使用到ContentResolver类,可以通过Context中的getContentResolver()方法获取到该类的实例。ContentResolver提供了很多方法用于对数据进行CRUD操作,分别是insert()\update()\delete()\query(),与SQLiteDatabase类似,只不过参数不同。ContentResolver中的CRUD方法都不接受表名,而是使用uri参数代替,这个参数被称为内容URI。内容 URI给内容提供器中的数据建立了唯一标识符,它主要由两部分组成,权限(authority)和路径(path) 。权限是用于对不同的应用程序做区分的,一般为了避免冲突,都会采用程序包名的方式来进行命名。比如某个程序的包名是 com.example.app,那么该程序对应的权限就可以命名为 com.example.app.provider。路径则是用于对同一应用程序中不同的表做区分的,通常都会添加到权限的后面。比如某个程序的数据库里存在两张表,table1和 table2,这时就可以将路径分别命名为/table1和/table2,然后把权限和路径进行组合,内容 URI就变成了 com.example.app.provider/table1和com.example.app.provider/table2。不过,目前还很难辨认出这两个字符串就是两个内容URI,我们还需要在字符串的头部加上协议声明。因此,内容 URI最标准的格式写法如下:

  1. content://com.example.app.provider/table1
  2. content://com.example.app.provider/table2

在得到了内容 URI字符串之后,我们还需要将它解析成 Uri对象才可以作为参数传入。解析的方法也相当简单,代码如下所示:

  1. Uri uri = Uri.parse("content://com.example.app.provider/table1")

现在我们就可以使用这个 Uri对象来查询 table1表中的数据了,代码如下所示:

  1. Cursor cursor = getContentResolver().query(
  2.         uri,
  3.         projection,
  4.         selection,
  5.         selectionArgs,
  6.         sortOrder);

查询完成后返回的仍然是一个 Cursor对象。

添加数据操作:

  1. ContentValues values = new ContentValues();
  2. values.put("column1", "text");
  3. values.put("column2", 1);
  4. getContentResolver().insert(uri, values);

更新数据操作:

  1. ContentValues values = new ContentValues();
  2. values.put("column1", "");
  3. getContentResolver().update(uri, values, "column1 = ? and column2 = ?", new
  4. String[] {"text", "1"});

删除数据操作:

  1. getContentResolver().delete(uri, "column2 = ?", new String[] { "1" });

二、创建自己的内容提供器

1、创建内容提供器的步骤

可以通过新建一个类去继承 ContentProvider的方式来创建一个自己的内容提供器。ContentProvider类中有六个抽象方法,我们在使用子类继承它的时候,需要将这六个方法全部重写。新建 MyProvider继承自 ContentProvider,代码如下所示:

  1. package ga.orlion.contactdemo;
  2.  
  3. import android.content.ContentProvider;
  4. import android.content.ContentValues;
  5. import android.database.Cursor;
  6. import android.net.Uri;
  7.  
  8. public class MyProvider extends ContentProvider {
  9.  
  10. @Override
  11. public boolean onCreate() {
  12. // TODO Auto-generated method stub
  13. return false;
  14. }
  15.  
  16. @Override
  17. public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
  18. // TODO Auto-generated method stub
  19. return null;
  20. }
  21.  
  22. @Override
  23. public String getType(Uri uri) {
  24. // TODO Auto-generated method stub
  25. return null;
  26. }
  27.  
  28. @Override
  29. public Uri insert(Uri uri, ContentValues values) {
  30. // TODO Auto-generated method stub
  31. return null;
  32. }
  33.  
  34. @Override
  35. public int delete(Uri uri, String selection, String[] selectionArgs) {
  36. // TODO Auto-generated method stub
  37. return 0;
  38. }
  39.  
  40. @Override
  41. public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
  42. // TODO Auto-generated method stub
  43. return 0;
  44. }
  45.  
  46. }
      1. onCreate()

        初始化内容提供器的时候调用。通常会在这里完成对数据库的创建和升级等操作,返回 true 表示内容提供器初始化成功,返回 false 则表示失败。注意,只有当存在ContentResolver尝试访问我们程序中的数据时,内容提供器才会被初始化

      2. query()

        从内容提供器中查询数据。使用 uri参数来确定查询哪张表,projection参数用于确定查询哪些列,selection和 selectionArgs参数用于约束查询哪些行,sortOrder参数用于对结果进行排序,查询的结果存放在 Cursor对象中返回。

      3. insert()

        向内容提供器中添加一条数据。使用 uri参数来确定要添加到的表,待添加的数据保存在 values参数中。添加完成后,返回一个用于表示这条新记录的 URI。

      4. update()

        更新内容提供器中已有的数据。使用 uri参数来确定更新哪一张表中的数据,新数据保存在 values参数中,selection和 selectionArgs参数用于约束更新哪些行,受影响的行数将作为返回值返回。

      5. delete()

        从内容提供器中删除数据。使用 uri参数来确定删除哪一张表中的数据,selection和 selectionArgs参数用于约束删除哪些行,被删除的行数将作为返回值返回

      6. getType()

        根据传入的内容 URI来返回相应的 MIME类型。

几乎每一个方法都会带有Uri这个参数, 这个参数也正是调用ContentResolver的增删改查方法时传递过来的。而现在,我们需要对传入的 Uri参数进行解析,从中分析出调用方期望访问的表和数据。

一个标准的内容 URI写法是这样的:content://com.example.app.provider/table1。这就表示调用方期望访问的是 com.example.app这个应用的 table1表中的数据。除此之外,我们还可以在这个内容 URI的后面加上一个 id,如下所示:

content://com.example.app.provider/table1/1。这就表示调用方期望访问的是 com.example.app这个应用的 table1表中 id为 1的数据。

内容URI的格式主要就只有以上两种,以路径结尾就表示期望访问该表中所有的数据,以 id结尾就表示期望访问该表中拥有相应 id的数据。我们可以使用通配符的方式来分别匹配这两种格式的内容 URI,规则如下:

    1. *:表示匹配任意长度的任意字符

    2. #:表示匹配任意长度的数字

所以,一个能够匹配任意表的内容 URI格式就可以写成:content://com.example.app.provider/*。而一个能够匹配 table1表中任意一行数据的内容 URI格式就可以写成:content://com.example.app.provider/table1/#。

接着, 我们再借助UriMatcher这个类就可以轻松地实现匹配内容URI的功能。 UriMatcher中提供了一个 addURI()方法,这个方法接收三个参数,可以分别把权限、路径和一个自定义代码传进去。这样,当调用 UriMatcher的 match()方法时,就可以将一个 Uri对象传入,返回值是某个能够匹配这个 Uri对象所对应的自定义代码,利用这个代码,我们就可以判断出调用方期望访问的是哪张表中的数据了。修改 MyProvider中的代码,如下所示:

  1. package com.example.contactdemo;
  2.  
  3. import android.content.ContentProvider;
  4. import android.content.ContentValues;
  5. import android.content.UriMatcher;
  6. import android.database.Cursor;
  7. import android.net.Uri;
  8.  
  9. public class MyProvider extends ContentProvider {
  10.  
  11. public static final int TABLE1_DIR = 0;
  12.  
  13. public static final int TABLE1_ITEM = 1;
  14.  
  15. public static final int TABLE2_DIR = 2;
  16.  
  17. public static final int TABLE2_ITEM = 3;
  18.  
  19. private static UriMatcher uriMatcher;
  20.  
  21. static {
  22. uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  23. uriMatcher.addURI("com.example.app.provider", "table1", TABLE1_DIR);
  24. uriMatcher.addURI("com.example.app.provider", "table1/#", TABLE1_ITEM);
  25. uriMatcher.addURI("com.example.app.provider", "table2", TABLE2_DIR);
  26. uriMatcher.addURI("com.example.app.provider", "table2/#", TABLE2_ITEM);
  27. }
  28.  
  29. @Override
  30. public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
  31.  
  32. switch (uriMatcher.match(uri)) {
  33.  
  34. case TABLE1_DIR:
  35. // 查询table1表中所有数据
  36. break;
  37. case TABLE1_ITEM:
  38. // 查询table2表中单条数据
  39. break;
  40. case TABLE2_DIR:
  41. // 查询table2表中所有数据
  42. break;
  43. case TABLE2_ITEM:
  44. //  查询table2表中单条数据
  45. break;
  46. default:
  47. break;
  48. }
  49. ....
  50. }
  51.  
  52. ...
  53.  
  54. }

可以看到,MyProvider中新增了四个整型常量,其中 TABLE1_DIR表示访问 table1表中的所有数据,TABLE1_ITEM 表示访问 table1表中的单条数据,TABLE2_DIR 表示访问table2表中的所有数据,TABLE2_ITEM表示访问 table2表中的单条数据。接着在静态代码块里我们创建了 UriMatcher的实例,并调用 addURI()方法,将期望匹配的内容 URI格式传递进去,注意这里传入的路径参数是可以使用通配符的。然后当 query()方法被调用的时候,就会通过 UriMatcher的 match()方法对传入的 Uri对象进行匹配,如果发现 UriMatcher中某个内容 URI格式成功匹配了该 Uri对象,则会返回相应的自定义代码,然后我们就可以判断出调用方期望访问的到底是什么数据了。上述代码只是以 query()方法为例做了个示范,其实 insert()、update()、delete()这几个方

法的实现也是差不多的,它们都会携带 Uri这个参数,然后同样利用 UriMatcher的 match()方法判断出调用方期望访问的是哪张表,再对该表中的数据进行相应的操作就可以了。

getType()方法是所有的内容提供器都必须提供的一个方法,用于获取 Uri对象所对应的 MIME类型。一个内容 URI所对应的 MIME字符串主要由三部分组分,Android对这三个部分做了如下格式规定:

    1. 必须以 vnd开头。

    2. 如果内容 URI以路径结尾,则后接 android.cursor.dir/,如果内容 URI以 id结尾,则后接 android.cursor.item/。

    3. 最后接上 vnd.<authority>.<path>。

所以,对于 content://com.example.app.provider/table1这个内容 URI,它所对应的 MIME类型就可以写成:vnd.android.cursor.dir/vnd.com.example.app.provider.table1

现在我们可以继续完善 MyProvider中的内容了,这次来实现 getType()方法中的逻辑,代码如下所示:

  1.         @Override
  2. public String getType(Uri uri) {
  3. switch (uriMatcher.match(uri)) {
  4. case TABLE1_DIR:
  5. return "vnd.android.cursor.dir/vnd.com.example.app.provider.table1";
  6. case TABLE1_ITEM:
  7. return "vnd.android.cursor.item/vnd.com.example.app.provider.table1";
  8. case TABLE2_DIR:
  9. return "vnd.android.cursor.dir/vnd.com.example.app.provider.table2";
  10. case TABLE2_ITEM:
  11. return "vnd.android.cursor.item/vnd.com.example.app.provider.table2";
  12. default:
  13. break;
  14. }
  15. return null;
  16. }

Android入门(十三)内容提供器的更多相关文章

  1. 入职小白随笔之Android四大组件——内容提供器详解(Content Provider)

    Content Provider 内容提供器简介 内容提供器(Content Provider)主要用于在不同的应用程序之间 实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的 ...

  2. Android中的内容提供器

    用途 不同于File, SharedPreferences和DataBase,Content Provider主要用于不同的应用程序间共享数据,允许一个程序安全的访问另一个程序中的数据. 用法 通过C ...

  3. Android入门(十四)内容提供器-实现跨程序共享实例

    原文链接:http://www.orlion.ga/661/ 打开SQLite博文中创建的 DatabaseDemo项目,首先将 MyDatabaseHelper中使用 Toast弹出创建数据库成功的 ...

  4. Android学习笔记(二十)——自定义内容提供器

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 如果我们想要实现跨程序共享数据的功能,官方推荐的方式就是使用内容提供器,可以通过新建一个类去继承 Conten ...

  5. Android学习笔记(十九)——内容提供器

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整 ...

  6. Android 创建内容提供器(ContentResolver)

    如果想实现跨程序共享数据的功能,官方推荐的方式就是使用内容提供器,可以通过新建一个类去继承 ContentResolver 的方式来创建一个自己的内容提供器. ContentProvider 类中有六 ...

  7. Android 内容提供器(Content Provider)介绍

    内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性.目前,使用内容 ...

  8. android: 创建自己的内容提供器

    我们学习了如何在自己的程序中访问其他应用程序的数据.总体来说思 路还是非常简单的,只需要获取到该应用程序的内容 URI,然后借助 ContentResolver 进行CRUD 操作就可以了.可是你有没 ...

  9. android: 内容提供器简介

    我们学了 Android 数据持久化的技术,包括文件存储.SharedPreferences 存 储.以及数据库存储.不知道你有没有发现,使用这些持久化技术所保存的数据都只能在当 前应用程序中访问.虽 ...

随机推荐

  1. MOTION-MATCHING IN UBISOFT’S FOR HONOR翻译

    http://www.gameanim.com/2016/05/03/motion-matching-ubisofts-honor/ Introducing For Honor with a vide ...

  2. 如何 在远程虚拟机 里 破解 最新版 SQL Prompt

    玩数据的人 经常 写写 SQL,SQL Prompt 是蛮好用的 辅助工具 ,现在 的 主流 破解工具 都是 需要  断开网路的 但是 现在 有些  开发环境 都是 在 云虚拟机 里,比如 客户方的. ...

  3. Android服务开机自启动

    新任务需要Android程序开机跑一个服务,查找资料得出如下方法: 用广播的方法监听系统启动事件:android.intent.action.BOOT_COMPLETED 并在AndroidManif ...

  4. ASP.Net MVC跳转,分为form的submit提交跳转和ajax跳转

    1,用jquery ajax跳转的话,需要在前台用window.location("跳转网址")来跳转,在success后使用 2,用原声的form的submit来跳转,如下图 3 ...

  5. 快速排序-java

    排序-快速排序 基本思想: 将数据划分为两部分,左边的所有元素都小于右边的所有元素:然后,对左右两边进行快速排序. 划分方法: 选定一个参考点(中间元素),所有元素与之相比较,小的放左边,大的放右边. ...

  6. 00.PHP学习建议

    各位师弟师妹,大家好~PHP不是我们专业的本该有的方向.我不知道大家为什么来学习这门语言,也许是自己了解之后喜欢这门语言(我想这种可能在我们专业是挺少的),也许是听守中哥说这门语言简单好学,为了躲避学 ...

  7. 要做linux运维工程师的朋友,必须要掌握以下几个工具才行 ...

    要做linux运维工程师的朋友,必须要掌握以下几个工具才行 ...  [复制链接]   发表于 2013-12-13 15:59 | 来自  51CTO网页 [只看他] 楼主           本人 ...

  8. iOS开发-UINavigationBar透明设置

    导航条最近需要设置成透明的形式,最开始想通过颜色clearColor设置,设置透明度,结果发现UINavigationItem无法显示显示,后来通过setBackgroundImage设置成功,不过会 ...

  9. 中国大学MOOC-陈越、何钦铭-数据结构-2016秋期末考试

    判断题: 1-1 N2logN和NlogN2具有相同的增长速度. (2分) 1-2 对一棵平衡二叉树,所有非叶结点的平衡因子都是0,当且仅当该树是完全二叉树.(2分) 1-3 无向连通图所有顶点的度之 ...

  10. guzzle调用失败-缺少guzzle

    用composer安装了,但是目前为止还有问题.开发环境是 WAMP PHP5.4.12. 已经打开PHP.ini 的SSL扩展,现在还是提示缺少 curl-ca-bundle.cr 报错 No sy ...