直接看代碼,有詳細註釋。
1.聯繫人的數據庫文件的位置
/data/data/com.android.providers.contacts/databases.contacts2.db
/data/data/com.android.providers.contacts/databases.contacts2.db
2.數據庫中重要的幾張表
contacts表:該表保存了所有的手機聯繫人,每個聯繫人佔一行,該表保存了聯繫人的ContactID、聯繫次數、
最後一次聯繫的時間、是否含有號碼、是否被添加到收藏夾等信息。可以與表的字段名相對應
理解。
raw_contacts表:該表保存了所有創建過的手機聯繫人,每個聯繫人佔一行,表裏有一列標識該聯繫人是否
被刪除,該表保存了兩個ID:RawContactID和ContactID,從而將contacts表和raw_contacts表
聯繫起來。該表保存了聯繫人的RawContactID、ContactID、聯繫次數、最後一次聯繫的時間
是否被添加到收藏夾、顯示的名字、用於排序的漢語拼音等信息。
mimetypes
表:該表定義了所有的MimeTypeID,即聯繫人的各個字段的唯一標誌。
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"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"
/>
這是對測試單元對應的權限和依賴庫:
<instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.example.contacts"></instrumentation>
<uses-library android:name="android.test.runner"/>