Android应用学习记录------通讯录的增,删,改,查

本文详细介绍了在Android中实现通讯录增删改查功能的方法,包括必要的权限设置、数据库表结构解析、以及如何使用ContentResolver进行数据操作。

转:http://lichangsong.blog.51cto.com/7997447/1306033


最近两天在做通讯录的增删改查功能。原以为Android会将通讯录的所有数据都集合到一个数据库表中,然后知道其ContentProvider提供Uri后,通过ContentResolver的query(),insert(),update(),delete()方法直接操作数据库的数据,j_0064.gif今天把其所有功能实现后,才发现并非自己当初想象的那么简单,好了,废话不多说。





一.权限

操作通讯录必须在AndroidManifest.xml中先添加2个权限,

1
2
< uses-permission android:name = "android.permission.READ_CONTACTS" />
< uses-permission android:name = "android.permission.WRITE_CONTACTS" />





二.通讯录数据库表介绍 (重点)



1.minetypes表


001424406.jpg




2.data表

001756305.jpg



3.raw_contacts表

002006950.jpg



002007600.jpg


注意: 3表第二个图是接第一图的右边的,因为大小的原因,截成了2张图。

首先说一下,联系人的信息操作前,必须把数据库的这3个表仔细看一下,看不懂也没关系,等会对进行增删改查的操作的时候,再回来对照数据库,这样你能够更加方便理解和记忆代码。否则,死记代码,过两天就忘的一干二净。

通讯录是存放在/data/data/com.android.providers.contacts/databases/contacts2.db,里面主要的表有:


(1)raw_contacts:存放联系人的 ID,_id属性为主键,声明为autoincrement,即不需要手动设置,其他属性也不需要手动设置就有默认值;display_name属性为姓名;sort_key属性可以用于查询后的排序

(2)mimetypes:存放数据的类型,比如"vnd.android.cursor.item/name"表示“姓名”类型的数据,"vnd.android.cursor.item/phone_v2"表示“电话”类型的数据;

(3)data:存放具体的数据;raw_contact_id 属性用来连接raw_contacts表,每条记录表示一个具体数据;raw_contact_id 需要重点记住,手机中显示的每一个联系人对应一个固定的raw_contact_idraw_contact_id 对应着 raw_contacts表的 _id ,他俩是相同的值,两个表之间的关系必须理清。(我刚开始就是没有理清表之间的关系,以及各个字段代表的意思,做起来就感觉很混乱,这3个表很重要)我们主要的数据(email、phone等)都存放在data表;

data1属性存放总数据;

data2属性:

-如果此记录存放姓名,则data2存放名;

-如果此记录存放电话,则data2存放类型,比如手机、家电;

-如果此记录存放组织,则data2存放类型,比如公司、其他;

-如果此记录存放地址,则data2存放类型,比如住宅,单位等






三.重要数据

URI

对raw_contacts表添加、删除、更新操作:

URI =content://com.android.contacts/raw_contacts;

Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;

对data表添加、删除、更新操作:
URI =content://com.android.contacts/data;
根据email对data表查询

URI =content://com.android.contacts/data/emails/filter/*

根据电话号码对data表查询

URI =content://com.android.contacts/data/phone/filter/*

如果要根据ID查询电话,可以
URI =content://com.android.contacts/data;

然后where条件为:raw_contact_id=? and mimetype = ?


MIMETYPE


电话:vnd.android.cursor.item/phone_v2
姓名:vnd.android.cursor.item/name
邮件:vnd.android.cursor.item/email_v2
通信地址:vnd.android.cursor.item/postal-address_v2
组织:vnd.android.cursor.item/organization
照片:vnd.android.cursor.item/photo

Data中的常量


Data._ID: "_id"

Data.DISPLAY_NAME:“display_name”

Data.DATA1:“data1”

Data.DATA2:“data2”

Data.RAW_CONTACT_ID:“raw_contact_id”

Data.MIMETYPE:“mimetype”







四.增删改查的实现


1.query


(1)查询所有的联系人

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//读取通讯录的全部的联系人
//需要先在raw_contact表中遍历id,并根据id到data表中获取数据
public void testReadAll(){
     //uri = content://com.android.contacts/contacts
     Uri uri = Uri.parse( "content://com.android.contacts/contacts" ); //访问raw_contacts表
     ContentResolver resolver = this .getContext().getContentResolver();
     //获得_id属性
     Cursor cursor = resolver.query(uri, new String []{Data._ID}, null , null , null );  
     while (cursor.moveToNext()){
         StringBuilder buf = new StringBuilder();
         //获得id并且在data中寻找数据 
         int id = cursor.getInt( 0 );
         buf.append( "id=" +id);
         uri = Uri.parse( "content://com.android.contacts/contacts/" +id+ "/data" );
         //data1存储各个记录的总数据,mimetype存放记录的类型,如电话、email等
         Cursor cursor2 = resolver.query(uri, new String []{Data.DATA1,Data.MIMETYPE}, null , null , null ); 
         while (cursor2.moveToNext()){
             String data = cursor2.getString(cursor2.getColumnIndex( "data1" ));
             if (cursor2.getString(cursor2.getColumnIndex( "mimetype" )).equals( "vnd.android.cursor.item/name" )){       //如果是名字
                 buf.append( ",name=" +data);
             }
             else if (cursor2.getString(cursor2.getColumnIndex( "mimetype" )).equals( "vnd.android.cursor.item/phone_v2" )){  //如果是电话
                 buf.append( ",phone=" +data);
             }
             else if (cursor2.getString(cursor2.getColumnIndex( "mimetype" )).equals( "vnd.android.cursor.item/email_v2" )){  //如果是email
                 buf.append( ",email=" +data);
             }
             else if (cursor2.getString(cursor2.getColumnIndex( "mimetype" )).equals( "vnd.android.cursor.item/postal-address_v2" )){ //如果是地址
                 buf.append( ",address=" +data);
             }
             else if (cursor2.getString(cursor2.getColumnIndex( "mimetype" )).equals( "vnd.android.cursor.item/organization" )){  //如果是组织
                 buf.append( ",organization=" +data);
             }
         }
         String str = buf.toString();
         Log.i( "Contacts" , str);
     }
}


(2)根据电话号码查询姓名

1
2
3
4
5
6
7
8
9
10
11
12
//根据电话号码查询姓名(在一个电话打过来时,如果此电话在通讯录中,则显示姓名)
     public void testReadNameByPhone(){
         String phone = "12345678" ;
         //uri=  content://com.android.contacts/data/phones/filter/#
         Uri uri = Uri.parse( "content://com.android.contacts/data/phones/filter/" +phone);    
         ContentResolver resolver = this .getContext().getContentResolver();
         Cursor cursor = resolver.query(uri, new String[]{Data.DISPLAY_NAME}, null , null , null ); //从raw_contact表中返回display_name
         if (cursor.moveToFirst()){
             Log.i( "Contacts" , "name=" +cursor.getString( 0 ));
         }
                                                                                                                             
}


2.Insert


注意:对某个联系人插入姓名、电话等记录时必须要插入Data.MIMETYPE(或者是"mimetype")属性,而不是插入"mimetype_id"!

比如:values.put(Data.MIMETYPE,"vnd.android.cursor.item/phone_v2")

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//一步一步添加数据
     public void testAddContacts(){
         //插入raw_contacts表,并获取_id属性
         Uri uri = Uri.parse( "content://com.android.contacts/raw_contacts" );
         ContentResolver resolver = this .getContext().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" , "zdong" );
         values.put( "data1" , "xzdong" );
         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" , "87654321" );
         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" , "xzdong@xzdong.com" );
         resolver.insert(uri, values);
     }

批量添加数据



核心代码:

(1)ContentProviderOperation operation = ContentProviderOperation.newInsert(uri).withValue("key","value").build();

(2)resolver.applyBatch("authorities",operations);//批量提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public void testAddContactsInTransaction() throws Exception {
     Uri uri = Uri.parse( "content://com.android.contacts/raw_contacts" );
     ContentResolver resolver = this .getContext().getContentResolver();
     ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
     // 向raw_contact表添加一条记录
     //此处.withValue("account_name", null)一定要加,不然会抛NullPointerException
     ContentProviderOperation operation1 = ContentProviderOperation
             .newInsert(uri).withValue( "account_name" , null ).build();
     operations.add(operation1);
     // 向data添加数据
     uri = Uri.parse( "content://com.android.contacts/data" );
     //添加姓名
     ContentProviderOperation operation2 = ContentProviderOperation
             .newInsert(uri).withValueBackReference( "raw_contact_id" , 0 )
             //withValueBackReference的第二个参数表示引用operations[0]的操作的返回id作为此值
             .withValue( "mimetype" , "vnd.android.cursor.item/name" )
             .withValue( "data2" , "xzdong" ).build();
     operations.add(operation2);
     //添加手机数据
     ContentProviderOperation operation3 = ContentProviderOperation
             .newInsert(uri).withValueBackReference( "raw_contact_id" , 0 )
             .withValue( "mimetype" , "vnd.android.cursor.item/phone_v2" )
             .withValue( "data2" , "2" ).withValue( "data1" , "0000000" ).build();
     operations.add(operation3);
     resolver.applyBatch( "com.android.contacts" , operations);


3.Delete


核心思想:
(1)先在raw_contacts表根据姓名(此处的姓名为name记录的data2的数据而不是data1的数据)查出id;
(2)在data表中只要raw_contact_id匹配的都删除;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void testDelete() throws Exception{
     String name = "xzdong" ;
     //根据姓名求id
     Uri uri = Uri.parse( "content://com.android.contacts/raw_contacts" );
     ContentResolver resolver = this .getContext().getContentResolver();
     Cursor cursor = resolver.query(uri, new String[]{Data._ID}, "display_name=?" , new String[]{name}, null );
     if (cursor.moveToFirst()){
         int id = cursor.getInt( 0 );
         //根据id删除data中的相应数据
         resolver.delete(uri, "display_name=?" , new String[]{name});
         uri = Uri.parse( "content://com.android.contacts/data" );
         resolver.delete(uri, "raw_contact_id=?" , new String[]{id+ "" });
     }
}




4.Update


核心思想:

(1)不需要更新raw_contacts,只需要更新data表;

(2)uri=content://com.android.contacts/data 表示对data表进行操作;

1
2
3
4
5
6
7
8
9
public void testUpdate() throws Exception{
     int id = 1 ;
     String phone = "999999" ;
     Uri uri = Uri.parse( "content://com.android.contacts/data" );//对data表的所有数据操作
     ContentResolver resolver = this .getContext().getContentResolver();
     ContentValues values = new ContentValues();
     values.put( "data1" , phone);
     resolver.update(uri, values, "mimetype=? and raw_contact_id=?" , new String[]{ "vnd.android.cursor.item/phone_v2" ,id+ "" }) 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值