一、通讯录应用介绍
通讯录应用是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,以及要访问通讯录需要的权限;
- <uses-permissionandroid:name="android.permission.READ_CONTACTS"/>
- <uses-permissionandroid:name="android.permission.WRITE_CONTACTS"/>
主要的通讯录程序为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存放类型,比如住宅,单位等;
四、对通信录做增删改查
简单的说:对通讯录操作就是对一个普通的ContentProvider操作;
1.Query
- //根据电话号码查询姓名(在一个电话打过来时,如果此电话在通讯录中,则显示姓名)
- publicvoidtestReadNameByPhone(){
- Stringphone="12345678";
- //uri=content://com.android.contacts/data/phones/filter/#
- Uriuri=Uri.parse("content://com.android.contacts/data/phones/filter/"+phone);
- ContentResolverresolver=this.getContext().getContentResolver();
- Cursorcursor=resolver.query(uri,newString[]{Data.DISPLAY_NAME},null,null,null);//从raw_contact表中返回display_name
- if(cursor.moveToFirst()){
- Log.i("Contacts","name="+cursor.getString(0));
- }
- }
(2)查询所有的联系人
- //读取通讯录的全部的联系人
- //需要先在raw_contact表中遍历id,并根据id到data表中获取数据
- publicvoidtestReadAll(){
- //uri=content://com.android.contacts/contacts
- Uriuri=Uri.parse("content://com.android.contacts/contacts");//访问raw_contacts表
- ContentResolverresolver=this.getContext().getContentResolver();
- Cursorcursor=resolver.query(uri,newString[]{Data._ID},null,null,null);//获得_id属性
- while(cursor.moveToNext()){
- StringBuilderbuf=newStringBuilder();
- intid=cursor.getInt(0);//获得id并且在data中寻找数据
- buf.append("id="+id);
- uri=Uri.parse("content://com.android.contacts/contacts/"+id+"/data");//如果要获得data表中某个id对应的数据,则URI为content://com.android.contacts/contacts/#/data
- Cursorcursor2=resolver.query(uri,newString[]{Data.DATA1,Data.MIMETYPE},null,null,null);//data1存储各个记录的总数据,mimetype存放记录的类型,如电话、email等
- while(cursor2.moveToNext()){
- Stringdata=cursor2.getString(cursor2.getColumnIndex("data1"));
- if(cursor2.getString(cursor2.getColumnIndex("mimetype")).equals("vnd.android.cursor.item/name")){//如果是名字
- buf.append(",name="+data);
- }
- elseif(cursor2.getString(cursor2.getColumnIndex("mimetype")).equals("vnd.android.cursor.item/phone_v2")){//如果是电话
- buf.append(",phone="+data);
- }
- elseif(cursor2.getString(cursor2.getColumnIndex("mimetype")).equals("vnd.android.cursor.item/email_v2")){//如果是email
- buf.append(",email="+data);
- }
- elseif(cursor2.getString(cursor2.getColumnIndex("mimetype")).equals("vnd.android.cursor.item/postal-address_v2")){//如果是地址
- buf.append(",address="+data);
- }
- elseif(cursor2.getString(cursor2.getColumnIndex("mimetype")).equals("vnd.android.cursor.item/organization")){//如果是组织
- buf.append(",organization="+data);
- }
- }
- Stringstr=buf.toString();
- Log.i("Contacts",str);
- }
- }
- //一步一步添加数据
- publicvoidtestAddContacts(){
- //插入raw_contacts表,并获取_id属性
- Uriuri=Uri.parse("content://com.android.contacts/raw_contacts");
- ContentResolverresolver=this.getContext().getContentResolver();
- ContentValuesvalues=newContentValues();
- longcontact_id=ContentUris.parseId(resolver.insert(uri,values));
- //插入data表
- uri=Uri.parse("content://com.android.contacts/data");
- //addName
- 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();
- //addPhone
- 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();
- //addemail
- 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);
- }
- <spanstyle="font-size:18px;">publicvoidtestAddContactsInTransaction()throwsException{
- Uriuri=Uri.parse("content://com.android.contacts/raw_contacts");
- ContentResolverresolver=this.getContext().getContentResolver();
- ArrayList<ContentProviderOperation>operations=newArrayList<ContentProviderOperation>();
- //向raw_contact表添加一条记录
- //此处.withValue("account_name",null)一定要加,不然会抛NullPointerException
- ContentProviderOperationoperation1=ContentProviderOperation
- .newInsert(uri).withValue("account_name",null).build();
- operations.add(operation1);
- //向data添加数据
- uri=Uri.parse("content://com.android.contacts/data");
- //添加姓名
- ContentProviderOperationoperation2=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);
- //添加手机数据
- ContentProviderOperationoperation3=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);
- }</span>
- publicvoidtestDelete()throwsException{
- Stringname="xzdong";
- //根据姓名求id
- Uriuri=Uri.parse("content://com.android.contacts/raw_contacts");
- ContentResolverresolver=this.getContext().getContentResolver();
- Cursorcursor=resolver.query(uri,newString[]{Data._ID},"display_name=?",newString[]{name},null);
- if(cursor.moveToFirst()){
- intid=cursor.getInt(0);
- //根据id删除data中的相应数据
- resolver.delete(uri,"display_name=?",newString[]{name});
- uri=Uri.parse("content://com.android.contacts/data");
- resolver.delete(uri,"raw_contact_id=?",newString[]{id+""});
- }
- }
核心思想:
(1)不需要更新raw_contacts,只需要更新data表;
(2)uri=content://com.android.contacts/data 表示对data表进行操作;
- publicvoidtestUpdate()throwsException{
- intid=1;
- Stringphone="999999";
- Uriuri=Uri.parse("content://com.android.contacts/data");//对data表的所有数据操作
- ContentResolverresolver=this.getContext().getContentResolver();
- ContentValuesvalues=newContentValues();
- values.put("data1",phone);
- resolver.update(uri,values,"mimetype=?andraw_contact_id=?",newString[]{"vnd.android.cursor.item/phone_v2",id+""})
- }