一、Content Provider基本概念
1、ContentProvider为存储和获取数据提供了统一的接口。ContentProvide对数据进行封装,不用关心数据存储的细节。使用表的形式来组织数据。
2、使用ContentProvider可以在不同的应用程序之间共享数据。
3、Android为常见的一些数据提供了默认的ContentProvider(包括音频、视频、图片和通讯录等)。
ContentProvider所提供的函数: query(),insert(),update(),delete(),getType(),onCreate()等。
二、URI(统一资源标识符)的使用方法
为系统的每一个资源给其一个名字,比方说通话记录。
1、每一个ContentProvider都拥有一个公共的URI,这个URI用于表示这个ContentProvider所提供的数据。
2、Android所提供的ContentProvider都存放在android.provider包中。 将其分为A,B,C,D 4个部分:
A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;"content://"
B:URI 的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的 类名。这个标识在元素的 authorities属性中说明:一般是定义该ContentProvider的包.类的名称;"content://hx.android.text.myprovider"
C:路径,通俗的讲就是数据库中要操作的表的名字
D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部
Uri写法1
Uri uri = Uri.parsecontent://media/internal/images") 这个URI将返回设备上存储的所有图片
content://contacts/people/ 这个URI将返回设备上的所有联系人信息
content://contacts/people/45 这个URI返回单个结果(联系人信息中ID为45的联系人记录)
Uri写法2
Uri person = ContentUris.withAppendedId(People.CONTENT_URI, 45);
然后执行数据查询: Cursor cur = managedQuery(person, null, null, null);
这个查询返回一个包含所有数据字段的游标,我们可以通过迭代这个游标来获取所有的数据:
三、ContentProvider的使用
实现: 应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法
自己实现ContentProvider不常见,因为可能不需要和别的应用程序交换数据。
因此下面主要介绍ContentProvider的使用
- 从Android 2.0 SDK开始有关联系人provider的类从android.provider.Contacts变成了android.provider.ContactsContract
- ContactsContract的子类ContactsContract.Contacts是一张表,代表了所有联系人的统计信息。比如联系人ID(—ID),查询键(LOOKUP_KEY),联系人的姓名(DISPLAY_NAME_PRIMARY),头像的id(PHOTO_ID)以及群组的id等等
- 在新的Contacts API中,联系人数据被安排三个主要的表中:contacts, raw contacts and data. 结构如下图所示:

一个contact(联系人)记录关联一个或多个RawContact(联系人来源,如Gmail)记录,每个RawContact记录又关联多个data(email, phone number等等)记录
package com.example.manhua;
import java.util.ArrayList;
import android.app.ListActivity;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class MainActivity extends ListActivity {
/*
* ListActivity的默认布局由一个位于屏幕中心的全屏列表构成。
* 如果你不想使用默认的布局,可以在onCreate()方法中通过setContentView()方法设定你自己的布局。
* 如果指定你自己定制的布局,你的布局中必须包含一个id为"@id/android:list"的ListView。
* 若你还指定了一个id为"@id/android:empty"的view,当ListView中没有数据要显示时,
* 这个view就会被显示,同时 ListView会被隐藏。
* */
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
displayRecords();
}
// <uses-permission android:name="android.permission.READ_CONTACTS"/>
private void displayRecords() {
Uri contactsUri = ContactsContract.Contacts.CONTENT_URI;
// 该数组中包含了所有要返回的字段
String proj1[] = new String[] { ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.HAS_PHONE_NUMBER , ContactsContract.Contacts.LOOKUP_KEY};
// declare a ArrayList object to store the data that will present to the
// user
Cursor curContacts = getContentResolver().query(contactsUri, proj1,
null, null, null);
ArrayList<String> contactsList = new ArrayList<String>();
String allPhoneNo = "";
if (curContacts.getCount() > 0) {
while (curContacts.moveToNext()) {
// get all the phone numbers if exist
if (curContacts.getInt(1) > 0) {
allPhoneNo = getAllPhoneNumbers(curContacts.getString(2));
}
contactsList.add(curContacts.getString(0) + " , " + allPhoneNo);
allPhoneNo = "";
}
}
// binding the data to ListView
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, contactsList));
ListView lv = getListView();
lv.setTextFilterEnabled(true);
}
/**
* Get all the phone numbers of a specific contact person
*
* @param lookUp_Key
* lookUp key for a specific contact
* @return a string containing all the phone numbers
*/
public String getAllPhoneNumbers(String lookUp_Key) {
String allPhoneNo = "";
// Phone info are stored in the ContactsContract.Data table
Uri phoneUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String[] proj2 = { ContactsContract.CommonDataKinds.Phone.NUMBER };
// using lookUp key to search the phone numbers
String selection = ContactsContract.Data.LOOKUP_KEY + "=?";
Cursor cur = getContentResolver().query(phoneUri, proj2, selection,
new String[] { lookUp_Key }, null);
while (cur.moveToNext()) {
allPhoneNo += cur.getString(0) + " ";
}
return allPhoneNo;
}
}
由于读取联系人比较的占用资源,为了提高用户的体验度。考虑将读取的过程放在线程里完成,推荐使用AsyncTask类
