一、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,现在再运行一遍,错误不见了。