Android手机通讯录解析(转)

1 、通讯录应用介绍

 

 

通讯录应用是 Android 自带的应用程序,我们看到此应用的时候,可能只认为这是一个应用,用数据库存储数据,但是实际上不是这样的。

 


通讯录是 ContentProvider 的应用,通讯录由两部分组成:
(1)com.android.providers.contacts
ContentProvider :真正存储数据的 ContentProvider
(2)com.android.contacts
:运用 ContentResolver 获取数据的图形用户界面;

 

 

2 、通讯录数据库目录结构

 

 

1 )、通讯录数据库目录结构的获取

打开 Eclipse 软件,调出虚拟机。如果已经创建过虚拟机,则只需要运行程序,如下图

如果没有创建就需要再去创建一个虚拟机。

 

 

调出虚拟机效果如下:

 

 

接下来就要:

通讯录是存放在 /data/data/com.android.providers.contacts/databases/contacts2.db 里的

 

 

接下来就是导出联系人的数据库:

 

 

导出后得到这样的数据库:

 

这个是 QLite Database Browser 工具

 

打开它把 contacts2.db 数据库拖进去就可以了。

 

得到如下:

 

 

查看数据库表中数据:

 

到此如何获取手机数据到此结束,前期工作完成。

 

 

3 、通讯录数据库结构介绍

 

 

这是手机通讯录直接相关联的几张表,圈出来的比较重要。

 

1 mimetype

 

2 contacts

 

此处的 name_raw_contact_id raw_contacts 表的主键

 

3 raw_contacts

 

 

此处 _id raw_contacts 表的主键, version 翻译后叫版本号 , 一般一个联系人创建后版本号就从 2 开始,当这个联系人每做一次操作后 version 都增加,一般是增加 1 ,但有时不确定反正他会增加。对于 Android 手机而言,它本身自带了一个通讯录,他对与联系人的删除操作就用户而言是删除了,因为在用户界面没有了该来联系人了。但是事实上 Android 并没有真正删除它。仅仅是在 raw_contacts 表中把 deleted 字段标记为了 1 ,意思是说 “1” 代表删除了, “0” 代表联系人没删除,是存在的。 contact_id 来自 contacts 表的主键。这样 contacts raw_contacts 联系在一起了。

 

 

4 data

 

 

data 表中的 mimetype_id 来自 mimetype 表, raw_contact_id 来自 raw_contacts 表。一般来说 data1 data15 的字段都是存放数据的。

 

 

其中 mimetype_id=5 代表电话号码 mimetype_id=7 代表姓名。当 mimetype_id=5 data1 存放电话号码, data2 存放电话号码的类型, data2=2, 代表电话号码为手机号。

 

 

2 3 、手机通讯录的操作介绍

 

 

1 )新增    这里介绍了两种方法

/**

* 将一组联系人添加到手机通讯录中

*

*  @param  Contacts

*  @param  context

*/

public   static   void   AddContact(ContactInfo[] Contacts, Context context) {

 

for   ( int  i = 0; i < Contacts.length; i++) {

 

ContentValues values =  new  ContentValues();

 

 

// 下面的操作会根据 RawContacts 表中已有的 rawContactId 使用情况自动生成新联系人的 rawContactId

 

Uri rawContactUri = context.getContentResolver().insert(

 

RawContacts. CONTENT_URI , values);

 

long   rawContactId = ContentUris. parseId (rawContactUri);

 

// data 表插入姓名数据

 

if   (Contacts[i].Name != "") {

 

values.clear();

 

values.put(Data. RAW_CONTACT_ID , rawContactId);

 

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

 

values.put(StructuredName. GIVEN_NAME , Contacts[i].Name);

 

context.getContentResolver().insert(

 

ContactsContract.Data. CONTENT_URI , values);

}

// data 表插入电话数据

if   (Contacts[i].Num != "") {

 

values.clear();

 

values.put(Data. RAW_CONTACT_ID , rawContactId);

 

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

 

values.put(Phone. NUMBER , Contacts[i].Num);

 

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

 

context.getContentResolver().insert(

 

ContactsContract.Data. CONTENT_URI , values);

}

}

}

 

 

 

/**

* 将单个联系人添加到通讯录中

*

*  @param  Contact

*  @param  context

*/

 

public   static   void   AddContact(ContactInfo Contact, Context context) {

 

ContentValues values =  new  ContentValues();

// 下面的操作会根据 RawContacts 表中已有的 rawContactId 使用情况自动生成新联系人的 rawContactId

 

Uri rawContactUri = context.getContentResolver().insert(

 

RawContacts. CONTENT_URI , values);

 

long   rawContactId = ContentUris. parseId (rawContactUri);

 

// data 表插入姓名数据

 

If   (Contact.Name != "") {

 

values.clear();

 

values.put(Data. RAW_CONTACT_ID , rawContactId);

 

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

 

values.put(StructuredName. GIVEN_NAME , Contact.Name);

 

context.getContentResolver().insert(

 

ContactsContract.Data. CONTENT_URI , values);

 

}

 

// data 表插入电话数据

 

if   (Contact.Num != "") {

 

values.clear();

 

values.put(Data. RAW_CONTACT_ID , rawContactId);

 

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

 

values.put(Phone. NUMBER , Contact.Num);

 

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

 

context.getContentResolver().insert(

 

ContactsContract.Data. CONTENT_URI , values);

}

}

 

 

public   static   void   testAddContacts(ContactInfo[] Contacts, Context context){

 

for   ( int  i = 0; i < Contacts.length; i++) {

 

// 插入 raw_contacts 表,并获取 _id 属性

 

Uri uri = Uri. parse ("content://com.android.contacts/raw_contacts"); // 获取操作的表的路径

 

ContentResolver resolver = context.getContentResolver(); // 类似 .NET 中的上下文对象或数据库操作

 

ContentValues values =  new  ContentValues(); // 定义一个联系人操作变量

 

long   contact_id = ContentUris. parseId (resolver.insert(uri, values));

 

// 插入 data

 

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

 

//add Name

 

values.put("raw_contact_id", contact_id);

 

values.put(Data. MIMETYPE ,"vnd.android.cursor.item/name");

 

values.put("data2", Contacts[i].Name);

 

values.put("data1", Contacts[i].Name);

 

resolver.insert(uri, values);

 

values.clear();

 

//add Phone

 

values.put("raw_contact_id", contact_id);

 

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

 

values.put("data2", "2");   // 手机

 

values.put("data1", Contacts[i].Num);

 

resolver.insert(uri, values);

 

values.clear();

 

}

}

 

 

public   static   void   testAddContacts(ContactInfo Contact, Context context){

 

// 插入 raw_contacts 表,并获取 _id 属性

 

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

 

ContentResolver resolver = context.getContentResolver();

 

ContentValues values =  new  ContentValues();

 

long   contact_id = ContentUris. parseId (resolver.insert(uri, values));

 

// 插入 data

 

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

 

//add Name

 

values.put("raw_contact_id", contact_id);

 

values.put(Data. MIMETYPE ,"vnd.android.cursor.item/name");

 

values.put("data2", Contact.Name);

 

values.put("data1", Contact.Name);

 

resolver.insert(uri, values);

 

values.clear();

 

//add Phone

 

values.put("raw_contact_id", contact_id);

 

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

 

values.put("data2", "2");   // 手机

 

values.put("data1", Contact.Num);

 

resolver.insert(uri, values);

 

values.clear();

 

/**   //add email

 

values.put("raw_contact_id", contact_id);

 

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

 

values.put("data2", "2");   // 单位

 

values.put("data1", "www.2cto.com");

 

resolver.insert(uri, values); */

}

 

 

 

2 )修改   此处也介绍两种方法针对 ID 的来源

/**

* 更新联系人

*

*  @param  context

* 上下文对象

*  @param  name

* 联系人姓名

*  @param  number

* 手机号

*  @param  ContactId

*ID (此 ID 是由通讯录数据库自动生成的 , 并且该 ID contacts 表中的主键)

*/

 

public   static   void   testUpdate(Context context, String name,

String number, String ContactId){

 

String  version="0";

 

String rawContactsId ="";

 

ContentResolver cr = context.getContentResolver();

 

// contacts 表中的主键查找 raw_contacts 表中的 ID 即主键

 

Cursor rawContactsIdCur = cr.query(RawContacts. CONTENT_URI ,

 

null , RawContacts. CONTACT_ID  + " = ?",

 

new   String[] { ContactId },  null );

 

if   (rawContactsIdCur.moveToFirst()) {

 

version = rawContactsIdCur.getString(rawContactsIdCur

 

.getColumnIndex(RawContacts. VERSION ));

 

// 获得 raw_contacts 表中的主键

 

rawContactsId = rawContactsIdCur.getString(rawContactsIdCur

 

.getColumnIndex(RawContacts. _ID ));

 

}

 

ContentResolver resolver = context.getContentResolver();

 

ContentValues values =  new  ContentValues();

 

Uri uri = Uri. parse ("content://com.android.contacts/data");// data 表的所有数据操作

 

resolver = context.getContentResolver();

 

values.clear();

 

values =  new  ContentValues();

 

values.put("data1", number);

 

// raw_contacts 表中的 ID data 表做相应的修改

 

resolver.update(uri, values, "mimetype=? and

raw_contact_id=?",  new  String[]{"vnd.android.cursor.item/phone_v2",rawContactsId}) ;

 

values.clear();

 

values.put("data2", name);

 

values.put("data1", name);

 

resolver.update(uri, values, "mimetype=? and

raw_contact_id=?",  new  String[]{"vnd.android.cursor.item/name",rawContactsId}) ;

 

rawContactsIdCur.close();

}

 

 

 

/**

* 更新联系人

*

*  @param  context

* 上下文对象

*  @param  name

* 联系人姓名

*  @param  number

* 手机号

*  @param  ContactId

*ID (此 ID 是由通讯录数据库自动生成的 , 并且该 ID raw_contacts 表中的主键)

*/

public   static   void   updateContact(Context context, String name,

 

String number, String ContactId)

{

 

ContentValues values =  new  ContentValues();

 

// 更新姓名

 

values.clear();

 

values.put(StructuredName. GIVEN_NAME , name);

 

context.getContentResolver().update(ContactsContract.Data. CONTENT_URI ,

 

values,

 

Data. RAW_CONTACT_ID  + "=? and " + Data. MIMETYPE  + "=?",

 

new   String[] { ContactId, StructuredName. CONTENT_ITEM_TYPE  });

 

// 更新电话

 

values.clear();

 

values.put(ContactsContract.CommonDataKinds.Phone. NUMBER , number);

 

context.getContentResolver().update(ContactsContract.Data. CONTENT_URI ,

 

values,

 

Data. RAW_CONTACT_ID  + "=? and " + Data. MIMETYPE  + "=?",

 

new   String[] { ContactId, Phone. CONTENT_ITEM_TYPE  });

 

}

 

 

 

3 )删除

 

 

这里是彻底删除,把 data,contacts,raw_contacts 表中的数据以并删除,而 Android 自带的手机通讯录删除操作不是真正意义上的删除,仅仅是将 raw_contacts 表中的 deleted 字段改为了 “1”

 

/**

* 删除联系人

*

*  @param  context

* 上下文对象

*  @param  ContactId

* 联系人 ID

*ID (此 ID 是请求数据传递过来的 , 并且该 ID raw_contacts 表中的主键)

*/

 

public   static   void   DeleteContact(Context context, String ContactId)

 

{

 

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

 

ContentResolver resolver = context.getContentResolver();

 

Cursor cursor =

resolver.query(uri,  new  String[]{RawContacts. _ID },"contact_id=?",  new  String[]{ContactId

},  null );

 

if (cursor.moveToFirst()){

 

int   id = cursor.getInt(0);

 

// 根据 id 删除 data 中的相应数据

 

resolver.delete(uri, "_id=?",  new  String[]{id+""});

 

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

 

resolver.delete(uri, "raw_contact_id=?",  new  String[]{id+""});

 

}

}

 

 

 

4 )读取联系人

 

/**

* 获取联系人

*

*  @return  list 数组,包含手机通讯录中的联系人

*/

 

private   List<Map<String, Object>> getContacts() {

 

List<Map<String, Object>> list =  new  ArrayList<Map<String, Object>>();

 

// 获取用来操作数据的类的对象,对联系人的基本操作都是使用这个对象

 

ContentResolver cr = getContentResolver();

 

// 查询 contacts 表的所有记录

 

Cursor cur = cr.query(ContactsContract.Contacts. CONTENT_URI ,  null ,

 

null ,  null ,  null );

 

String deleted = "1";

 

String version = "0";

// 如果记录不为空

 

if   (cur.getCount() > 0) {

 

// 游标初始指向查询结果的第一条记录的上方,执行 moveToNext 函数会判断

 

// 下一条记录是否存在,如果存在,指向下一条记录。否则,返回 false

 

while   (cur.moveToNext()) {

 

// 取得联系人的 ID 索引值

 

String contactId = cur.getString(cur

 

.getColumnIndex(ContactsContract.Contacts. _ID ));

 

if (contactId== null )

 

{

 

contactId="No Id";

 

}

 

// 取得联系人的名字索引

 

int   nameIndex = cur.getColumnIndex(PhoneLookup. DISPLAY_NAME );

 

String name = cur.getString(nameIndex);

 

if (name== null )

 

{

 

name="No name";

 

}

 

String rawContactsId = "";

 

String id = cur.getString(cur

 

.getColumnIndex(ContactsContract.Contacts. _ID ));

 

//  str  += "ID:" + id + "\n"; 二、对联系人的基本操作 (4)

 

// 读取 rawContactsId

 

Cursor rawContactsIdCur = cr.query(RawContacts. CONTENT_URI ,

 

null , RawContacts. CONTACT_ID  + " = ?",

 

new   String[] { id },  null );

 

// 该查询结果一般只返回一条记录,所以我们直接让游标指向第一条记录

 

if   (rawContactsIdCur.moveToFirst()) {

 

// 读取第一条记录的 RawContacts._ID 列的值

 

rawContactsId = rawContactsIdCur.getString(rawContactsIdCur

 

.getColumnIndex(RawContacts. _ID ));

 

deleted = rawContactsIdCur.getString(rawContactsIdCur

 

.getColumnIndex(RawContacts. DELETED ));

 

version = rawContactsIdCur.getString(rawContactsIdCur

 

.getColumnIndex(RawContacts. VERSION ));

 

}

 

rawContactsIdCur.close();

 

// 读取号码

 

Cursor PhoneCur = cr.query(

 

ContactsContract.CommonDataKinds.Phone. CONTENT_URI ,

 

null ,

 

ContactsContract.CommonDataKinds.Phone. RAW_CONTACT_ID

 

+ " =?",  new  String[] { rawContactsId },  null );

 

// 上面的 ContactsContract.CommonDataKinds.Phone.CONTENT_URI

 

// 可以用下面的 phoneUri 代替

 

//  Uri

 

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

 

 

 

 

// 二、对联系人的基本操作 (6)

 

// 一个联系人可能有多个号码,需要遍历

 

if (!PhoneCur.moveToNext())

 

{

 

// 获取电话号码为空的情况即游标未找到的情况

 

String  number="No number";

 

// // 获取号码类型

 

Map<String, Object> map =  new  HashMap<String, Object>();

 

map.put("phone", number + ",");

 

map.put("name", name + "|");

 

map.put("version", version + ",");

 

map.put("deleted", deleted + ",");

 

map.put("id", contactId + ",");

 

list.add(map);

 

}

 

else

 

{

 

// 号获取码

 

String number = PhoneCur

 

.getString(PhoneCur

 

.getColumnIndex(ContactsContract.CommonDataKinds.Phone. NUMBER ));

 

// // 获取号码类型

 

Map<String, Object> map =  new  HashMap<String, Object>();

 

map.put("phone", number + ",");

 

map.put("name", name + "|");

 

map.put("version", version + ",");

 

map.put("deleted", deleted + ",");

 

map.put("id", contactId + ",");

 

list.add(map);

 

}

 

while   (PhoneCur.moveToNext()) {

 

// 号获取码

 

String number = PhoneCur

 

.getString(PhoneCur

 

.getColumnIndex(ContactsContract.CommonDataKinds.Phone. NUMBER ));

 

if (number== null )

 

{

 

number="No number";

 

}

 

// // 获取号码类型

 

Map<String, Object> map =  new  HashMap<String, Object>();

 

map.put("phone", number + ",");

 

map.put("name", name + "|");

 

map.put("version", version + ",");

 

map.put("deleted", deleted + ",");

 

map.put("id", contactId + ",");

 

list.add(map);

 

}

 

PhoneCur.close();// 关闭游标

 

}

 

}

 

return   list;

 

}

 

}

全部评论

相关推荐

喜欢走神的孤勇者练习时长两年半:爱华,信华,等华,黑华
点赞 评论 收藏
分享
狠赚笔第一人:学计算机自己不努力怪大环境?我大一就拿到了美团大厂的offer,好好看看自己有没有努力查看图片
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务