原文链接: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最标准的格式写法如下:

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

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

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

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

Cursor cursor = getContentResolver().query(
        uri,
        projection,
        selection,
        selectionArgs,
        sortOrder);

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

添加数据操作:

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

更新数据操作:

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

删除数据操作:

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

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

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

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

package ga.orlion.contactdemo;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri; public class MyProvider extends ContentProvider { @Override
public boolean onCreate() {
// TODO Auto-generated method stub
return false;
} @Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
return null;
} @Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
} @Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
return null;
} @Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
} @Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
} }
      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中的代码,如下所示:

package com.example.contactdemo;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri; public class MyProvider extends ContentProvider { public static final int TABLE1_DIR = 0; public static final int TABLE1_ITEM = 1; public static final int TABLE2_DIR = 2; public static final int TABLE2_ITEM = 3; private static UriMatcher uriMatcher; static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI("com.example.app.provider", "table1", TABLE1_DIR);
uriMatcher.addURI("com.example.app.provider", "table1/#", TABLE1_ITEM);
uriMatcher.addURI("com.example.app.provider", "table2", TABLE2_DIR);
uriMatcher.addURI("com.example.app.provider", "table2/#", TABLE2_ITEM);
} @Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { switch (uriMatcher.match(uri)) { case TABLE1_DIR:
// 查询table1表中所有数据
break;
case TABLE1_ITEM:
// 查询table2表中单条数据
break;
case TABLE2_DIR:
// 查询table2表中所有数据
break;
case TABLE2_ITEM:
//  查询table2表中单条数据
break;
default:
break;
}
....
} ... }

可以看到,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()方法中的逻辑,代码如下所示:

        @Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case TABLE1_DIR:
return "vnd.android.cursor.dir/vnd.com.example.app.provider.table1";
case TABLE1_ITEM:
return "vnd.android.cursor.item/vnd.com.example.app.provider.table1";
case TABLE2_DIR:
return "vnd.android.cursor.dir/vnd.com.example.app.provider.table2";
case TABLE2_ITEM:
return "vnd.android.cursor.item/vnd.com.example.app.provider.table2";
default:
break;
}
return null;
}

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. Thinkphp内置截取字符串函数

    Thinkphp内置了一个可以媲美smarty的模板引擎,给我们带来了很大的方便.调用函数也一样,可以和smarty一样调用自己需要的函数,而官方也内置了一些常用的函数供大家调用. 比如今天我们说的截 ...

  2. 图解HTTPS

    看到一篇讲解HTTPS交互的文章,讲得很清楚,备忘一下 来自无网不剩的博客 我们都知道HTTPS能够加密信息,以免敏感信息被第三方获取.所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTP ...

  3. alfresco install in linux, and integrated with tesseract ocr

    本文描述在Linux系统上安装Alfresco的步骤: 1. 下载安装文件:alfresco-community-5.0.d-installer-linux-x64.bin 2. 增加执行权限并执行: ...

  4. Unity3d中Update()方法的替身

    在网上看到一些资料说Unity3d的Update方法是如何如何不好,影响性能.作为一个菜鸟,之前我还觉得挺好用的,完全没用什么影响性能的问题存在.现在发现确实有很大的问题,我习惯把一大堆检测判断放在U ...

  5. 使用yum时,保留下载包设置

    配置yum保留已经下载的rpm包,供以后升级或重新安装时使用.修改/etc/yum.conf[main]cachedir=/home/soft1/yumcachekeepcache=1debuglev ...

  6. PHP版微信公共平台消息主动推送,突破订阅号一天只能发送一条信息限制

    2013年10月06日最新整理. PHP版微信公共平台消息主动推送,突破订阅号一天只能发送一条信息限制 微信公共平台消息主动推送接口一直是腾讯的私用接口,相信很多朋友都非常想要用到这个功能. 通过学习 ...

  7. goalng 发布的版本中自动加上 git revision

    概述 起因是这样的,在编译发布 golang 工程时,希望版本号中包含有 git revision number. 但是,没有commit之前,是没法知道 revision number 的,comm ...

  8. TFS 改服务器IP 域名 端口方法

    长春电信伴随着开始的严打,所有未备案的80,8080等常用web端口都被封,使得原用8080作为服务端口的tfs代码服务器无法使用,现提供方法如下: 1.关掉VS 2.去掉要改的解决方案的sln文件的 ...

  9. 【腾讯Bugly干货分享】揭秘:微信是如何用libco支撑8亿用户的

    本文来自于腾讯bugly开发者社区,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/58203cfcd149ba305c5ccf85 作者:Leiffy 导语 lib ...

  10. 人人都是 DBA(VIII)SQL Server 页存储结构

    当在 SQL Server 数据库中创建一张表时,会在多张系统基础表中插入所创建表的信息,用于管理该表.通过目录视图 sys.tables, sys.columns, sys.indexes 可以查看 ...