转自:http://blog.csdn.net/xiazdong/article/details/7713419
一、通讯录应用介绍
通讯录应用是Android自带的应用程序,我们看到此应用的时候,可能只认为这是一个应用,用数据库存储数据,但是实际上不是这样的。
通讯录是ContentProvider的应用,通讯录由两部分组成:
(1)com.android.providers.contacts的ContentProvider:真正存储数据的ContentProvider
(2)com.android.contacts:运用ContentResolver获取数据的图形用户界面;
二、获取ContactProvider的源代码
Android源代码: http://my.oschina.net/zhanglubing/blog/40623 用Git获取;
如果要获取ContactProvider,则安装git,并打开git bash,输入
git clone https://android.googlesource.com/platform/packages/providers/ContactsProvider.git 即可;
目录结构如下:
为何要获取ContactProvider的源代码呢?
因为如果要访问ContentProvider,必须要了解URI的设置(authority,path等);只有查看源代码才能够知道;
AndroidManifest.xml为清单文件,列出了ContactProvider的authorities,以及要访问通讯录需要的权限;
[html]
view plain
copy
<span style="font-family:KaiTi_GB2312;font-size:16px;"> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" /></span>
主要的通讯录程序为ContactsProvider2.Java
authorities=contacts或com.android.contacts;
三、通讯录数据库结构介绍
表结构如下:
通讯录是存放在/data/data/com.android.providers.contacts/databases/contacts2.db,里面主要的表有:
(1)raw_contacts:存放联系人的ID,
_id属性为主键,声明为autoincrement,即不需要手动设置,其他属性也不需要手动设置就有默认值;
display_name属性为姓名;
(2)mimetypes:存放数据的类型,比如"vnd.android.cursor.item/name"表示“姓名”类型的数据,"vnd.android.cursor.item/phone_v2"表示“电话”类型的数据;
(3)data:存放具体的数据;
raw_contact_id属性用来连接raw_contacts表,每条记录表示一个具体数据;我们主要的数据(email、phone等)都存放在data表;
data1属性存放总数据;
data2属性:
-如果此记录存放姓名,则data2存放名;
-如果此记录存放电话,则data2存放类型,比如手机、家电;
-如果此记录存放组织,则data2存放类型,比如公司、其他;
-如果此记录存放地址,则data2存放类型,比如住宅,单位等;
四、编程提示
URI
对raw_contacts表添加、删除、更新操作:
URI = content://com.android.contacts/raw_contacts;
对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”
五、对通信录做增删改查
简单的说:对通讯录操作就是对一个普通的ContentProvider操作;
1.Query
(1)根据电话号码查询姓名
[java]
view plain
copy
public void testReadNameByPhone(){ String phone = "12345678"; 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); if(cursor.moveToFirst()){ Log.i("Contacts", "name="+cursor.getString(0)); } }
(2)查询所有的联系人
[java]
view plain
copy
public void testReadAll(){ Uri uri = Uri.parse("content://com.android.contacts/contacts"); //访问raw_contacts表 ContentResolver resolver = this.getContext().getContentResolver(); Cursor cursor = resolver.query(uri, new String[]{Data._ID}, null, null, null); while(cursor.moveToNext()){ StringBuilder buf = new StringBuilder(); int id = cursor.getInt(0); buf.append("id="+id); uri = Uri.parse("content://com.android.contacts/contacts/"+id+"/data"); //如果要获得data表中某个id对应的数据,则URI为content://com.android.contacts/contacts/#/data 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")){ 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.Insert
(1)一步一步添加数据
注意:对某个联系人插入姓名、电话等记录时必须要插入Data.MIMETYPE(或者是"mimetype")属性,而不是插入"mimetype_id"!
比如:values.put(Data.MIMETYPE,"vnd.android.cursor.item/phone_v2");
[java]
view plain
copy
public void testAddContacts(){ 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)); uri = Uri.parse("content://com.android.contacts/data"); 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(); 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(); 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); }
(2)批量添加数据
核心代码:
(1)ContentProviderOperation operation = ContentProviderOperation.newInsert(uri).withValue("key","value").build();
(2)resolver.applyBatch("authorities",operations);//批量提交
[java]
view plain
copy
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>(); ContentProviderOperation operation1 = ContentProviderOperation .newInsert(uri).withValue("account_name", null).build(); operations.add(operation1); uri = Uri.parse("content://com.android.contacts/data"); ContentProviderOperation operation2 = ContentProviderOperation .newInsert(uri).withValueBackReference("raw_contact_id", 0) .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匹配的都删除;
[java]
view plain
copy
public void testDelete()throws Exception{ String name = "xzdong"; 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); 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表进行操作;
[java]
view plain
copy
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+""}) }