访问通信录中的联系人和添加联系人

论坛 期权论坛 编程之家     
选择匿名的用户   2021-5-26 09:13   459   0

通信录的相关数据也保存在数据库文件中,保存的路径为:/data/data/com.android.providers.contacts/databases/contacts2.db。我们在通讯录界面上添加联系人时,内部实际上是通过ContentProvider向数据库中添加记录。通讯录的界面应用与ContentProvider应用是分开的。通讯录界面应用的保存位置为:/data/data/com.android.contacts

常用的几张表如下:

raw_contacts:存放联系人的ID

字段display_name:存放姓+名的组合,便于快速得到用户的姓名。注意,当向该表添加联系人时该字段是为null的,只有在向data表中添加姓名时,才会发出update语句来更新该字段。

data:存放联系人的详细信息,如姓名、手机等,主要几个字段的含义如下:

字段data1:存放具体数据

字段data2:对于电话号码,存放类型:家庭电话、手机号等,2代表手机号

对于邮箱,存放类型

对于姓名,存放名字部分,data3存放姓氏部分

字段mimetype_id:区分数据的类型,5-电话数据,6-姓名数据,1-email数据,对应表mimetypes中的记录ID

这两个表的对应关系是:raw_contacts 1:N data

mimetypes:数据的类型,如下图:






calls:呼叫记录

使用ContentResolver对通信录中的数据进行添加、删除、修改和查询操作,需要加入读写联系人信息的权限

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

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

添加与查询如下:

加入读取联系人信息的权限

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

content://com.android.contacts/contacts 操作的数据是联系人信息Uri

content://com.android.contacts/data/phones 联系人电话Uri

content://com.android.contacts/data/emails 联系人Email Uri

ContentProvider的名字可以在源码的文件ContactsProvider\AndroidManifest.xml中找到。如下所示,定义了两个标识,分别为:contacts 或com.android.contacts,如果需要查询具体的业务路径,需要查看类ContactsProvider2中提供的功能,可以通过查找“UriMatcher”来找到。

<provider android:name="ContactsProvider2"

android:authorities="contacts;com.android.contacts"

android:label="@string/provider_label"

android:multiprocess="false"

android:readPermission="android.permission.READ_CONTACTS"

android:writePermission="android.permission.WRITE_CONTACTS">

<path-permission

android:pathPrefix="/search_suggest_query"

android:readPermission="android.permission.GLOBAL_SEARCH"/>

<path-permission

android:pathPrefix="/search_suggest_shortcut"

android:readPermission="android.permission.GLOBAL_SEARCH"/>

<path-permission

android:pathPattern="/contacts/.*/photo"

android:readPermission="android.permission.GLOBAL_SEARCH"/>

<grant-uri-permission android:pathPattern=".*" />

</provider>

ContactsProvider2中提供的部分业务路径:

static{

// Contacts URI matching table

final UriMatcher matcher = sUriMatcher;

matcher.addURI(ContactsContract.AUTHORITY, "contacts",CONTACTS);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/#",CONTACTS_ID);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data",CONTACTS_ID_DATA);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/#/entities", CONTACTS_ID_ENTITIES);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/#/suggestions",

AGGREGATION_SUGGESTIONS);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/#/suggestions/*",

AGGREGATION_SUGGESTIONS);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo",CONTACTS_ID_PHOTO);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/#/display_photo",

CONTACTS_ID_DISPLAY_PHOTO);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/#/stream_items",

CONTACTS_ID_STREAM_ITEMS);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter",CONTACTS_FILTER);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/filter/*", CONTACTS_FILTER);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*",CONTACTS_LOOKUP);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/lookup/*/data", CONTACTS_LOOKUP_DATA);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/lookup/*/photo",

CONTACTS_LOOKUP_PHOTO);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/lookup/*/#", CONTACTS_LOOKUP_ID);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/lookup/*/#/data",

CONTACTS_LOOKUP_ID_DATA);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/lookup/*/#/photo",

CONTACTS_LOOKUP_ID_PHOTO);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/lookup/*/display_photo",

CONTACTS_LOOKUP_DISPLAY_PHOTO);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/lookup/*/#/display_photo",

CONTACTS_LOOKUP_ID_DISPLAY_PHOTO);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/lookup/*/entities",

CONTACTS_LOOKUP_ENTITIES);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/lookup/*/#/entities",

CONTACTS_LOOKUP_ID_ENTITIES);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/lookup/*/stream_items",

CONTACTS_LOOKUP_STREAM_ITEMS);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/lookup/*/#/stream_items",

CONTACTS_LOOKUP_ID_STREAM_ITEMS);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/as_vcard/*", CONTACTS_AS_VCARD);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_multi_vcard/*",

CONTACTS_AS_MULTI_VCARD);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/strequent/", CONTACTS_STREQUENT);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/strequent/filter/*",

CONTACTS_STREQUENT_FILTER);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*",CONTACTS_GROUP);

matcher.addURI(ContactsContract.AUTHORITY,"contacts/frequent", CONTACTS_FREQUENT);

… …

}

读取联系人信息

Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

while (cursor.moveToNext()) {

StringcontactId =cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));

Stringname = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));

Cursorphones =getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,

null,

ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+contactId,

null, null);

while (phones.moveToNext()) {

String phoneNumber = phones.getString(phones.getColumnIndex(

ContactsContract.CommonDataKinds.Phone.NUMBER));

Log.i("RongActivity", "phoneNumber="+phoneNumber);

}

phones.close();

Cursor emails =getContentResolver().query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,

null,

ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = " +contactId,

null, null);

while (emails.moveToNext()) {

// This would allow you get several email addresses

String emailAddress =emails.getString(emails.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));

Log.i("RongActivity", "emailAddress="+ emailAddress);

}

emails.close();

}

cursor.close();

==================== 添加联系人===========================

方法一:

/**

* 首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获取系统返回的rawContactId

* 这时后面插入data表的依据,只有执行空值插入,才能使插入的联系人在通讯录里面可见

*/

publicvoid testInsert() {

ContentValuesvalues = new ContentValues();

//首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获取系统返回的rawContactId

UrirawContactUri =this.getContext().getContentResolver().insert(RawContacts.CONTENT_URI, values);

longrawContactId = ContentUris.parseId(rawContactUri);

//往data表入姓名数据

values.clear();

values.put(Data.RAW_CONTACT_ID,rawContactId);

values.put(Data.MIMETYPE,StructuredName.CONTENT_ITEM_TYPE);//内容类型

values.put(StructuredName.GIVEN_NAME,"李天山");

this.getContext().getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI,values);

//往data表入电话数据

values.clear();

values.put(Data.RAW_CONTACT_ID,rawContactId);

values.put(Data.MIMETYPE,Phone.CONTENT_ITEM_TYPE);

values.put(Phone.NUMBER,"13921009789");

values.put(Phone.TYPE,Phone.TYPE_MOBILE);

this.getContext().getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI,values);

//往data表入Email数据

values.clear();

values.put(Data.RAW_CONTACT_ID,rawContactId);

values.put(Data.MIMETYPE,Email.CONTENT_ITEM_TYPE);

values.put(Email.DATA,"liming@itcast.cn");

values.put(Email.TYPE,Email.TYPE_WORK);

this.getContext().getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI,values);

}

方法二:批量添加,处于同一个事务中

publicvoid testSave() throws Throwable{

//文档位置:reference\android\provider\ContactsContract.RawContacts.html

ArrayList<ContentProviderOperation>ops = new ArrayList<ContentProviderOperation>();

intrawContactInsertIndex = ops.size();

ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)

.withValue(RawContacts.ACCOUNT_TYPE,null)

.withValue(RawContacts.ACCOUNT_NAME,null)

.build());

//文档位置:reference\android\provider\ContactsContract.Data.html

ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)

.withValueBackReference(Data.RAW_CONTACT_ID,rawContactInsertIndex)

.withValue(Data.MIMETYPE,StructuredName.CONTENT_ITEM_TYPE)

.withValue(StructuredName.GIVEN_NAME,"赵薇")

.build());

ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)

.withValueBackReference(Data.RAW_CONTACT_ID,rawContactInsertIndex)

.withValue(Data.MIMETYPE,Phone.CONTENT_ITEM_TYPE)

.withValue(Phone.NUMBER,"13671323809")

.withValue(Phone.TYPE,Phone.TYPE_MOBILE)

.withValue(Phone.LABEL, "手机号")

.build());

ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)

.withValueBackReference(Data.RAW_CONTACT_ID,rawContactInsertIndex)

.withValue(Data.MIMETYPE,Email.CONTENT_ITEM_TYPE)

.withValue(Email.DATA,"liming@itcast.cn")

.withValue(Email.TYPE,Email.TYPE_WORK)

.build());

ContentProviderResult[]results = this.getContext().getContentResolver()

.applyBatch(ContactsContract.AUTHORITY,ops);

for(ContentProviderResultresult : results){

Log.i(TAG,result.uri.toString());

}

}

下面创建应用contacts,ApplicationName:访问通讯录,Package Name:cn.itcast.contacts,Create Activity:MainActivity。在该项目中通过单元测试来获取联系人信息。

1. 配置单元测试的环境/contacts/AndroidManifest.xml

<?xml version="1.0"encoding="utf-8"?>

<manifestxmlns:android="http://schemas.android.com/apk/res/android"

package="cn.itcast.contacts"

android:versionCode="1"

android:versionName="1.0">

<application android:icon="@drawable/icon"android:label="@string/app_name">

<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>

<uses-sdk android:minSdkVersion="8" />

<instrumentationandroid:targetPackage="cn.itcast.contacts"android:name="android.test.InstrumentationTestRunner" />

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

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

</manifest>

所需权限可以在源码中的AndroidManifest.xml中查找到。


2. 创建测试类ContactsTest

package cn.itcast.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 extendsAndroidTestCase {

privatestatic final String TAG = "ContactsTest";

//获取所有联系人

publicvoid testContacts()throws Exception{

Uriuri = Uri.parse("content://com.android.contacts/contacts");

ContentResolverresolver = getContext().getContentResolver();

//查询raw_contacts._id

Cursorcursor = resolver.query(uri, new String[]{"_id"}, null, null, null);

while(cursor.moveToNext()){

intcontactid = cursor.getInt(0);

StringBuildersb = new StringBuilder("contactid=");

sb.append(contactid);

//content://com.android.contacts/contacts/#/data

uri= Uri.parse("content://com.android.contacts/contacts/"+contactid+ "/data");

//查询data表中相关的字段

Cursordatacursor = resolver.query(uri, newString[]{"mimetype","data1","data2"}, null, null,null);

while(datacursor.moveToNext()){

Stringdata = datacursor.getString(datacursor.getColumnIndex("data1"));

Stringtype = datacursor.getString(datacursor.getColumnIndex("mimetype"));

if("vnd.android.cursor.item/name".equals(type)){//姓名

sb.append(",name="+data);

}elseif("vnd.android.cursor.item/email_v2".equals(type)){//email

sb.append(",email="+data);

}elseif("vnd.android.cursor.item/phone_v2".equals(type)){//phone

sb.append(",phone="+data);

}

}

Log.i(TAG,sb.toString());

}

}

//根据号码获取联系人的姓名

publicvoid testContactNameByNumber()throws Exception{

Stringnumber = "18601025011";

Uriuri = Uri.parse("content://com.android.contacts/data/phones/filter/"+number);

ContentResolverresolver = getContext().getContentResolver();

Cursorcursor = resolver.query(uri, newString[]{"display_name"}, null, null, null);

if(cursor.moveToFirst()){

Stringname = cursor.getString(0);

Log.i(TAG,name);

}

cursor.close();

}

//添加联系人。缺点:由多个操作完成,无法保证全部都成功

publicvoid testAddContact()throws Exception{

Uriuri = Uri.parse("content://com.android.contacts/raw_contacts");

ContentResolverresolver = getContext().getContentResolver();

ContentValuesvalues = 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.clear();

values.put("raw_contact_id",contactid);

values.put("mimetype","vnd.android.cursor.item/phone_v2");

values.put("data2","2");

values.put("data1","13671323507");

resolver.insert(uri,values);

//添加Email

values.clear();

values.put("raw_contact_id",contactid);

values.put("mimetype","vnd.android.cursor.item/email_v2");

values.put("data2","2");

values.put("data1","zhangxx@csdn.net");

resolver.insert(uri,values);

}

//在同一个事务中完成联系人各项数据的添加

publicvoid testAddContact2()throws Exception{

Uriuri = Uri.parse("content://com.android.contacts/raw_contacts");

ContentResolverresolver = getContext().getContentResolver();

ArrayList<ContentProviderOperation>operations = new ArrayList<ContentProviderOperation>();

ContentProviderOperationop1 = ContentProviderOperation.newInsert(uri)

.withValue("account_name",null) //account_name专门用于存放google的登录帐号

.build();

operations.add(op1);

//注意:因为是在一个事务中完成的,所以不知道raw_contact_id的值,

// 因此在设置raw_contact_id时使用withValueBackReference

// .withValueBackReference("raw_contact_id",0)的含义是使用第一个操作对象添加完成后所返回的记录ID作为字段的值

uri= Uri.parse("content://com.android.contacts/data");

ContentProviderOperationop2 = ContentProviderOperation.newInsert(uri)

.withValueBackReference("raw_contact_id",0)

.withValue("mimetype","vnd.android.cursor.item/name")

.withValue("data2","李小龙")

.build();

operations.add(op2);

ContentProviderOperationop3 = ContentProviderOperation.newInsert(uri)

.withValueBackReference("raw_contact_id",0)

.withValue("mimetype","vnd.android.cursor.item/phone_v2")

.withValue("data1","13560650505")

.withValue("data2","2")

.build();

operations.add(op3);

ContentProviderOperationop4 = ContentProviderOperation.newInsert(uri)

.withValueBackReference("raw_contact_id",0)

.withValue("mimetype","vnd.android.cursor.item/email_v2")

.withValue("data1","liming@sohu.com")

.withValue("data2","2")

.build();

operations.add(op4);

resolver.applyBatch("com.android.contacts",operations);

}

}


分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP