data表:该表保存了所有创建过的手机测联系人的所有信息,每个字段占一行 ,该表保存了两个ID:MimeTypeI D和RawContactID,从而将data表和raw_contacts表联系起来。联系人的所有信息保存在列data1至data 15中,各列中保存的内容根据MimeTypeID的不同而不同。如保存号码(MimeTypeID=5)的那行数据中 ,data1列保存号码,data2列保存号码类型(手机号码/家庭号码/工作号码等)。
package com.example.test; import java.util.ArrayList; import android.content.ContentProviderOperation; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.test.AndroidTestCase; import android.util.Log; public class ContactsTest extends AndroidTestCase { private static final String tag="ContactsTest"; public void testContacts() throws Exception //测试查询联系人 { /* Content URI 是一种用于标识 Provider 数据的 URI。 Content URI 包括了整个 Provider 的符号名称(authority)和表名(path)。 调用客户端的方法访问 Provider 数据表时, 表的 Content URI 是参数之一。Uri uri=Uri.parse("content://com.android.contacts/contacts"); */ //这里的字符串com.android.contacts 是 Provider 的 authority 部分, 字符串 contacts 是数据表的 path 部分。 字符串 content:// (scheme)是必须指定的,以表明这是一个 Content URI。 Uri uri=Uri.parse("content://com.android.contacts/contacts"); ContentResolver resolver=this.getContext().getContentResolver(); Cursor cursor=resolver.query(uri, new String[]{"_id"}, null, null, null); while(cursor.moveToNext()) { int contactid=cursor.getInt(0); StringBuffer sb=new StringBuffer("contactid="); sb.append(contactid); uri=Uri.parse("content://com.android.contacts/contacts/"+contactid+"/data"); /* Cursor = getContentResolver().query( uri, // 联系人的URI mProjection, // 需要返回的列 mSelectionClause, // 查询条件 mSelectionArgs, // 查询条件的参数 mSortOrder); // 返回结果的排序要求 */ Cursor datacursor=resolver.query(uri //联系人的URI , new String[]{"mimetype","data1","data2"}//需要返回的列 , null //查询条件 , null //查询条件的参数 , null); //返回结果的排序要求 while(datacursor.moveToNext()) { String data=datacursor.getString(datacursor.getColumnIndex("data1")); String type=datacursor.getString(datacursor.getColumnIndex("mimetype")); if("vnd.android.cursor.item/name".equals(type)) { sb.append(",name="+data); } else if("vnd.android.cursor.item/email_v2".equals(type)) { sb.append(",email="+data); }else if("vnd.android.cursor.item/phone_v2".equals(type)){ sb.append(",phone="+data); } } Log.i(tag, sb.toString()); } cursor.close(); } public void testContactsNameByNumer() throws Exception { String number="15241499053"; //Provider 提供了对单条记录的访问能力,只要在 URI 后面跟一个 ID 值即可。 例如,要根据电话找到联系人,只需要在后面加上number,可以使用以下 Content URI: Uri uri=Uri.parse("content://com.android.contacts/data/phones/filter/"+number); ContentResolver resolver=this.getContext().getContentResolver(); Cursor cursor=resolver.query(uri, new String[]{"display_name"}, null, null, null); while(cursor.moveToNext()) { String name=cursor.getString(0); Log.i(tag,name); } cursor.close(); } /* 调用 ContentResolver.insert() 方法可以将数据插入 Provider 到中去。 该方法将在 Provider 中插入新数据行,并返回一个指向改行数据的 Content URI。 以下代码将在 com.android.contacts Provider 中插入一条新的联系人: 新行的数据存放在一个 ContentValues 对象中, 对象中,这个对象类似于只包含一条数据的游标。 该对象中的各个字段的类型可以各不相同。如果不需要指定值,可以用 ContentValues.putNull() 方法置为 null。 上述代码并没有给 _ID 字段赋值,因为这个字段是由系统自动维护的。 Provider 会自动给插入行的 _ID 字段赋一个唯一值,并且通常把它作为表的主键使用。 */ public void testAddContacts() throws Exception { Uri uri=Uri.parse("content://com.android.contacts/raw_contacts"); ContentResolver resolver=getContext().getContentResolver(); ContentValues values=new ContentValues(); long contactid=ContentUris.parseId(resolver.insert(uri, values)); uri=Uri.parse("content://com.android.contacts/data"); //添加姓名 values.put("raw_contact_id", contactid); values.put("mimetype", "vnd.android.cursor.item/name"); values.put("data2", "王超"); resolver.insert(uri, values); //添加电话 values.put("raw_contact_id", contactid); values.put("mimetype", "vnd.android.cursor.item/phone_v2"); values.put("data2", "2"); values.put("data1", "4399101"); resolver.insert(uri, values); //Email values.put("raw_contact_id", contactid); values.put("mimetype", "vnd.android.cursor.item/email_v2"); values.put("data2", "2"); values.put("data1", "[email protected]"); resolver.insert(uri, values); } /* 在开发应用时,访问 Provider 还有其他三种重要的形式: 批量访问:通过 ContentProviderOperation 类的一些方法,可以创建批量访问任务,并通过 ContentResolver.applyBatch() 来提交。 异步查询:在单独的线程中执行查询。有一种方案是用 CursorLoader 对象来实现。在指南 Loaders 中给出了示例。 利用 Intent 访问数据: 虽然不能向 Provider 直接发送 Intent,但可以向 Provider 所在应用发送 Intent, 通常这些应用都具备修改 Provider 数据的能力。 下面这种就是以通过 ContentProviderOperation进行的批量添加。 */ public void testAddContact2() throws Exception{ Uri uri=Uri.parse("content://com.android.contacts/raw_contacts"); ContentResolver resolver=getContext().getContentResolver(); //创建一个 ContentProviderOperation 对象的数组,并通过 ContentResolver.applyBatch() 方法将它传给 Content Provider。 ArrayList<ContentProviderOperation> operations=new ArrayList<ContentProviderOperation>(); ContentProviderOperation op1=ContentProviderOperation.newInsert(uri) .withValue("account_name", null) .build(); operations.add(op1); /* * 在调用时不是指定某个 Content URI,而是要给出 Content Provider 的 authority。 * 数组中的每个 ContentProviderOperation 对象可以对不同的数据表进行操作。 * ContentResolver.applyBatch() 返回的结果也是数组。 */ uri=Uri.parse("ontent://com.android.contacts/data"); ContentProviderOperation op2=ContentProviderOperation.newInsert(uri) .withValueBackReference("raw_contact_id", 0) .withValue("mimetype", "vnd.android.cursor.item/name") .withValue("data2", "李小龙") .build(); operations.add(op2); ContentProviderOperation op3=ContentProviderOperation.newInsert(uri) .withValueBackReference("raw_contact_id", 0) .withValue("mimetype", "vnd.android.cursor.item/phone_v2") .withValue("data1", "110119") .withValue("data2", "2") .build(); operations.add(op3); ContentProviderOperation op4=ContentProviderOperation.newInsert(uri) .withValueBackReference("raw_contact_id", 0) .withValue("mimetype", "vnd.android.cursor.item/email_v2") .withValue("data1", "[email protected]") .withValue("data2", "2") .build(); operations.add(op4); resolver.applyBatch("com.android.contacts", operations); } }
完成以上测试代码还需要添加对联系人表操作的响应权限。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.contacts" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <uses-library android:name="android.test.runner"/> </application> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.example.contacts"></instrumentation> <uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.WRITE_CONTACTS"/>" </manifest>
这是对联系人操作对应的权限:
<uses-permission android:name="android.permission.READ_CONTACTS"
<instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.example.contacts"></instrumentation>
<uses-library android:name="android.test.runner"/>