Android数据的四种存储方式之 —— Content Provider

一、Content Provider 简介

我们说Android应用程序的四个核心组件是:Activity、Service、Broadcast Receiver 和 Content Provider。那么这个Content Provider到底是什么呢?它和SQLite又有什么区别呢?

我们知道如果用SQLite来存储数据的话,只能在本应用程序之间进行增、删查,绝对访问不到别的应用程序的数据。因为在Android中,应用程序彼此之间相互独立的,它们都运行在自己独立的虚拟机中。

那么怎么访问别的应用程序的数据呢?那么我们就要用到Content Provider了。

同样可以把Content Provider看成一个关系型数据库,只不过那比SQLite多了一个功能:Content Provider是所有应用程序之间数据存储和检索的桥梁,它使得各个应用程序之间实现数据共享。


二、Content Provider的常用方法

    //查询  
    query(Uri, String[], String, String[], String);  
    //插入  
    insert(Uri, ContentValues);  
    //更新  
    update(Uri, ContentValues, String, String[]);   
    //删除  
    delete(Uri, String, String[]);  
    //获得MIME数据类型  
    getType(Uri);


三、Content Provider的表结构

Content Provider 将其存储的数据以数据表的形式提供给访问者,在数据表中每一行为一条记录,每一列为具有特定类型和意义的数据。每一条数据记录都包括一个 "_ID" 数值字段,改字段唯一标识一条数据。

_ID

NUMBER

NUMBER_KEY

LABEL

NAME

TYPE

13

(425) 555 6677

425 555 6677

Kirkland office

Bully Pulpit

TYPE_WORK

44

(212) 555-1234

212 555 1234

NY apartment

Alan Vain

TYPE_HOME

45

(212) 555-6657

212 555 6657

Downtown office

Alan Vain

TYPE_MOBILE

53

201.555.4433

201 555 4433

Love Nest

Rex Cars

TYPE_HOME


四、使用现成的Content Provider

有些数据是很常用的,会被很多应用程序访问。于是Android为这些常用的数据提供了Content Provider,这些常用的数据包括:音频、视频、图片和通讯录等等。我们不需要自己实现Content Provider,直接使用现成的Content Provider就OK了。Android所提供的Content Provider都存放在android.provider包当中。


五、Content Provider的统一操作接口:URI

Content Provider实现应用程序之间数据共享的简单原理:一个程序可以使用Content Provider 定义一个URI,提供统一的操作接口,其他程序可以通过此URI访问指定的数据,进行数据的增、删、改、查。

何谓URI?请往下看:

每一个Content Provider 都对外提供一个能够唯一标识自己数据集(data set)的URI, 如果一个Content Provider管理多个数据集,其将会为每个数据集分配一个独立的URI。Content Provider就是通过URI对象来共享其数据的。

URI的格式图如下:

各个部分的组成:

A:标准前缀,是固定的,"content://"是用来标识数据是由Content Provider管理的 schema。

B:URI的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的类名。这个标识在 元素的 authorities属性中说明:一般是定义该ContentProvider的包.类的名称

C:需要访问的数据字段名称。

D:如果URI中包含表示需要获取的记录的_ID;如何有D部分,则就返回该_ID对应的数据,否则表示返回整张表的数据


六、实现读取Android系统通讯录提供的Content Provider的简单的例子

1、新建一个ContentProvider项目。

2、res/layout/main.xml内容省略,就是制作一个查询按钮。

3、ContentProviderActivity.java的内容如下:

package com.tianjf;

import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class ContentProviderActivity extends Activity {

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		Button button = (Button) findViewById(R.id.button);

		OnClickListener onClickListener = new OnClickListener() {

			@Override
			public void onClick(View v) {

				// 在Content Provider使用过程中,还需要借用ContentResolver对象间接来操作ContentProvider来获取数据。
				// ContentResolver通过应用程序的getContentResolver()方法获得。一般情况下,ContentResolver是单实例的,
				// 但是可以有多个ContentResolver在不用的应用程序和不同的进程之间和ContentResolver交互。
				ContentResolver contentResolver = getContentResolver();
				// 获得所有的联系人
				Cursor cursor = contentResolver.query(
						ContactsContract.Contacts.CONTENT_URI, null, null,
						null, null);
				// 循环遍历
				if (cursor.moveToFirst()) {
					// 获得id列的列index
					int idColumn = cursor
							.getColumnIndex(ContactsContract.Contacts._ID);
					// 获得displayName列的列index
					int displayNameColumn = cursor
							.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);

					do {
						// 根据列的index获得联系人的ID号
						String contactId = cursor.getString(idColumn);

						// 根据列的index获得联系人姓名
						String disPlayName = cursor
								.getString(displayNameColumn);

						Toast.makeText(ContentProviderActivity.this,
								"联系人姓名:" + disPlayName, Toast.LENGTH_LONG)
								.show();

						// 查看该联系人有多少个电话号码。如果没有这返回值为0
						int phoneCount = cursor
								.getInt(cursor
										.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));

						if (phoneCount > 0) {

							// 获得联系人的电话号码列表
							Cursor phonesCursor = getContentResolver()
									.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
											null,
											ContactsContract.CommonDataKinds.Phone.CONTACT_ID
													+ " = " + contactId, null,
											null);

							if (phonesCursor.moveToFirst()) {
								do {
									// 遍历所有的电话号码
									String phoneNumber = phonesCursor
											.getString(phonesCursor
													.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
									Toast.makeText(
											ContentProviderActivity.this,
											"联系人电话:" + phoneNumber,
											Toast.LENGTH_LONG).show();
								} while (phonesCursor.moveToNext());
							}
						}
					} while (cursor.moveToNext());
				}
			}
		};

		button.setOnClickListener(onClickListener);
	}
}

运行程序回报一下错误:

04-16 14:45:10.752: E/AndroidRuntime(302): java.lang.SecurityException: Permission Denial: 
reading com.android.providers.contacts.ContactsProvider2 uri content://com.android.contacts/contacts 
from pid=302, uid=10040 requires android.permission.READ_CONTACTS

原来还要在AndroidManifest.xml加上下面的权限声明

<uses-permission android:name="android.permission.READ_CONTACTS"/>

OK,现在再运行一遍,错误不见了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值