Android入门(十三)内容提供器

原文链接: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;
	}
时间: 2024-12-31 15:17:08

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

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

Content Provider 内容提供器简介 内容提供器(Content Provider)主要用于在不同的应用程序之间 实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访数据的安全性,目前,使用内容提供器是Android实现跨程序共享数据的标准方式. 在正式学习内容提供器之前,我们需要先掌握另外一个非常重要的知识--Android运行时权限,因为 在学习内容提供器时,我们会用到这方面的知识.另外运行时权限的知识在以后我们的开发过程中还会经常的涉

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

原文链接:http://www.orlion.ga/661/ 打开SQLite博文中创建的 DatabaseDemo项目,首先将 MyDatabaseHelper中使用 Toast弹出创建数据库成功的提示去除掉,因为跨程序访问时我们不能直接使用 Toast.然后添加一个 DatabaseProvider类,代码如下所示: package ga.orlion.databasedemo; import android.content.ContentProvider; import android.c

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

//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 如果我们想要实现跨程序共享数据的功能,官方推荐的方式就是使用内容提供器,可以通过新建一个类去继承 ContentProvider 的方式来创建一个自己的内容提供器: 一.继承ContentProvider的六个方法: ContentProvider 类中有六个抽象方法,我们需要使用子类去继承它,并重写六个方法,我们先来认识这六个类.新建 MyProvider继承自 ContentProvide,代码如下所示: 1 p

android学习十二(android的Content Provider(内容提供器)的使用)

文件存储和SharePreference存储以及数据存储一般为了安全,最好用于当前应用程序中访问和存储数据.内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性.目前使用内容提供器是android实现跨程序共享数据的标准方式.内容提供器可以选择只对一部分数据进行共享,从而保证我们的程序中的隐私数据不会有泄漏的风险. 内容提供器的用法一般有两种,一种是使用现有的内容提

android笔记 : Content provider内容提供器

内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能. 内容提供器的用法一般有两种,一种是使用现有的内容提供器来读取和操作相应程序中的数据,另一种是创建自己的内容提供器给我们程序的数据提供外部访问接口. 第一种方法:使用ContentResolver来读取和操作相应程序中的数据 1.用parse方法将内容 URI 字符串解析成 Uri 对象. uri(Uniform Resource identifier)指的是统一资源标识符Uri uri = Uri .

Android 跨程序共享数据,探究内容提供器

内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性.目前,使用内容提供器是 Android 实现跨程序共享数据的标准方式. 不同于文件存储和 SharePreferences 存储中的两种全局可读写操作模式,内容提供器可以选择只对哪一部分数据进行共享,从而保证我们程序中的隐私数据不会有泄露的风险. 访问其他程序中的数据: 对于每一个应用程序来说,如果想要访问内容提

android: 内容提供器简介

我们学了 Android 数据持久化的技术,包括文件存储.SharedPreferences 存 储.以及数据库存储.不知道你有没有发现,使用这些持久化技术所保存的数据都只能在当 前应用程序中访问.虽然文件和 SharedPreferences 存储中提供了 MODE_WORLD_READABLE 和 MODE_WORLD_WRITEABLE 这两种操作模式,用于供给其他的应用程序访问当前应用 的数据,但这两种模式在 Android 4.2 版本中都已被废弃了.为什么呢?因为 Android 官

Android基础总结(6)——内容提供器

前面学习的数据持久化技术包括文件存储.SharedPreferences存储以及数据库存储技术保存的数据都只能被当前应用程序所访问.虽然文件存储和SharedPreferences存储中提供了MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE这两种操作模式,可以实现不同应用程序间的数据共享,但是这两种模式在Android4.2版本中就已经被废弃了.目前,Android系统推荐使用一种更加安全可靠的内容提供器技术. 内容提供器(Content Provider)主要用

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

//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访数据的安全性.当一个应用程序通过内容提供器对其数据提供了外部访问接口,任何其他的应用程序就都可以对这部分数据进行访问.Android 系统中自带的电话簿.短信.媒体库等程序都提供了类似的访问接口,这就使得第三方应用程序可以充分地利用这部分数据来实现更