一.前言

     1.1 Android的电话本的机制.

Android的电话本通过contentProvider封装好的。我们只要通过sdk提供的Uri和字段来对其进行增、删、改、查。

     1.2 权限 

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

     1.3 找到ContentProvider维护的Sqlist数据库文件( .db)

ContentProvider其实自己管理一个Sqlist数据库文件( .db)。这个文件的路径为/data/data/com.android.providers.contacts/databases/contacts2.db。如图:

   1.4 查看ContentProvider维护的Sqlist数据库文件( .db)

在模拟器中的电话本里创建几个联系人,打开1.2中的.db文件,可以用数据库查看工具SQLite Expert Professional打开看下,如图:

从上图,可以看出左边是.db文件的表,点开各表后可以看出主要的表有raw_contacts,contacts,data

二. api

      2.1 三张主表.

从api中可以看到android.provider.ContactsContract是sdk2.0的类库,从api和上面的图都可以看出关于电话本主要信息都存在 ContactsContract.Data, ContactsContract.RawContacts, ContactsContract.Contacts 三张表里

2.1.1 以上三张表的关联关系.

ContactsContract.Data, ContactsContract.RawContacts, ContactsContract.Contacts 三张表的关联,

ContactsContract.RawContacts表里包含ContactsContract.Contacts的contact_id;ContactsContract.Data表里有ContactsContract.RawContacts的raw_contact_id,和ContactsContract.Contacts的contact_id

   2.2 各数据对应的类库,电话本各字段的数据结构

2.2.1 Email 对应ContactsContract.CommonDataKinds.Email

Type Alias Data column
String ADDRESS DATA1 Email address itself.
int TYPE DATA2 Allowed values are:

  • TYPE_CUSTOM. Put the actual type in LABEL.
  • TYPE_HOME
  • TYPE_WORK
  • TYPE_OTHER
  • TYPE_MOBILE
String LABEL DATA3  

Email数据有三个字段存储:ADDRESS为Email值;TYPE为类型,当为自定义(TYPE_CUSTOM)时,LABEL字段要写入用户自定义的类型;

2.2.2 IM 对应 ContactsContract.CommonDataKinds.Im

Type Alias Data column
String DATA DATA1  
int TYPE DATA2 Allowed values are:

  • TYPE_CUSTOM. Put the actual type in LABEL.
  • TYPE_HOME
  • TYPE_WORK
  • TYPE_OTHER
String LABEL DATA3  
String PROTOCOL DATA5

Allowed values:

  • PROTOCOL_CUSTOM. Also provide the actual protocol name as CUSTOM_PROTOCOL.
  • PROTOCOL_AIM
  • PROTOCOL_MSN
  • PROTOCOL_YAHOO
  • PROTOCOL_SKYPE
  • PROTOCOL_QQ
  • PROTOCOL_GOOGLE_TALK
  • PROTOCOL_ICQ
  • PROTOCOL_JABBER
  • PROTOCOL_NETMEETING
String CUSTOM_PROTOCOL DATA6

Im有5个字段

2.2.3 Phone 对应 ContactsContract.CommonDataKinds.Phone

Type Alias Data column
String NUMBER DATA1  
int TYPE DATA2 Allowed values are:

  • TYPE_CUSTOM. Put the actual type in LABEL.
  • TYPE_HOME
  • TYPE_MOBILE
  • TYPE_WORK
  • TYPE_FAX_WORK
  • TYPE_FAX_HOME
  • TYPE_PAGER
  • TYPE_OTHER
  • TYPE_CALLBACK
  • TYPE_CAR
  • TYPE_COMPANY_MAIN
  • TYPE_ISDN
  • TYPE_MAIN
  • TYPE_OTHER_FAX
  • TYPE_RADIO
  • TYPE_TELEX
  • TYPE_TTY_TDD
  • TYPE_WORK_MOBILE
  • TYPE_WORK_PAGER
  • TYPE_ASSISTANT
  • TYPE_MMS
String LABEL DATA3

2.2.4 Postal address 通讯地址 对应 ContactsContract.CommonDataKinds.StructuredPostal

Type Alias Data column
String FORMATTED_ADDRESS DATA1  
int TYPE DATA2 Allowed values are:

  • TYPE_CUSTOM. Put the actual type in LABEL.
  • TYPE_HOME
  • TYPE_WORK
  • TYPE_OTHER
String LABEL DATA3  
String STREET DATA4  
String POBOX DATA5 Post Office Box number
String NEIGHBORHOOD DATA6  
String CITY DATA7  
String REGION DATA8  
String POSTCODE DATA9  
String COUNTRY DATA10

最长用的有 TYPE:类型;STREET:街道;CITY:市;REGION:省;POSTCODE:邮政编码;

三.代码

3.1根据API写代码.

在api里 ContactsContract.Data 和ContactsContract.RawContacts文档里有关于insert ,update, delete,query的代码,显示出操作各自的表的代码。可以根据这些来完成我们自己的逻辑。

3.2 查询 (查出全部联系人,在只显示姓名)需要如图:

需求分析:由于列表中只需要姓名,所以在查询表时就只查询出姓名信息就好。当点击某个联系人再查出Email,phone等详细信息。

   3.2.1 查询联系人总表代码:

说明:由于姓名可以直接在ContactsContract.Contacts表里查到,所以如下

public static final String[] PROJECTION_CONTACTS = { Contacts._ID,Contacts.PHOTO_ID, Contacts.IN_VISIBLE_GROUP,Contacts.HAS_PHONE_NUMBER, Contacts.DISPLAY_NAME,Contacts.CUSTOM_RINGTONE };/*** wu0wu* * 功能:查询所有联系人PROJECTION_CONTACTS信息* * */public static void _getContacts(ContentResolver cr) {Cursor cursorContact = null;try {cursorContact = cr.query(ContactsContract.Contacts.CONTENT_URI,PROJECTION_CONTACTS, Contacts.IN_VISIBLE_GROUP + "=1",null, null);Log.e("wu0wu", "联系人个数=" + cursorContact.getCount());int[] indexs = getColumnIndexs(PROJECTION_CONTACTS, cursorContact);while (cursorContact.moveToNext()) {Log.e("wu0wu", "------------------------------------");for (int i = 0; i < PROJECTION_CONTACTS.length; i++) {String value = cursorContact.getString(indexs[i]);Log.e("wu0wu", PROJECTION_CONTACTS[i] + "=" + value);}}} catch (Exception e) {Log.e("wu0wu", e.toString());} finally {if (cursorContact != null) {cursorContact.close();}}}private static int[] getColumnIndexs(String[] projections, Cursor c) {int[] ret = new int[projections.length];for (int i = 0; i < projections.length; i++) {ret[i] = c.getColumnIndex(projections[i]);}return ret;}

3.2.2 根据contactId查询联系人详细

// phoneprivate static final String[] PROJECTION_PHONENUMBER_CONTACT = {Phone.NUMBER, Phone.TYPE, Phone.LABEL };/* DISPLAY_NAME唯一性 */private static final String[] PROJECTION_DISPLAYNAME_CONTACT = { StructuredName.DISPLAY_NAME };// Emailprivate static final String[] PROJECTION_EAMIL_CONTACT = { Email.DATA1,Email.TYPE, Email.LABEL };// IMprivate static final String[] PROJECTION_IM_CONTACT = new String[] {Im.DATA, Im.TYPE, Im.LABEL, Im.PROTOCOL };// addressprivate static final String[] PROJECTION_ADDRESS_CONTACT = new String[] {StructuredPostal.STREET, StructuredPostal.CITY,StructuredPostal.REGION, StructuredPostal.POSTCODE,StructuredPostal.COUNTRY, StructuredPostal.TYPE,StructuredPostal.LABEL, StructuredPostal.POBOX,StructuredPostal.NEIGHBORHOOD, };// Organizationprivate static final String[] PROJECTION_ORGANIZATION_CONTACT = new String[] {Organization.COMPANY, Organization.TYPE, Organization.LABEL,Organization.TITLE };// noteprivate static final String[] PROJECTION_NOTES_CONTACT = new String[] { Note.NOTE };// nicknameprivate static final String[] PROJECTION_NICKNAMES_CONTACT = new String[] {Nickname.NAME, Nickname.TYPE, Nickname.LABEL };// websiteprivate static final String[] PROJECTION_WEBSITES_CONTACT = new String[] {Website.URL, Website.TYPE, Website.LABEL };/*** 功能:根据contactId查询联系人详细* * 在android.provider.ContactsContract.Data表里查询* */public static void _getContactByContactId(ContentResolver cr,String contactId) {Cursor c = null;c = cr.query(Data.CONTENT_URI, null, Data.CONTACT_ID + "=?",new String[] { contactId }, null);String mimeType = null;String[] contentValue = null;ArrayList<String[]> displayNameList = new ArrayList<String[]>();// 存显示名ArrayList<String[]> phoneList = new ArrayList<String[]>();// 存电话号码,可多个ArrayList<String[]> emailList = new ArrayList<String[]>();// 存Email,可多个ArrayList<String[]> imList = new ArrayList<String[]>();// 存im,可多个ArrayList<String[]> postalList = new ArrayList<String[]>();// 存postal地址,可多个ArrayList<String[]> organizationList = new ArrayList<String[]>();// 存organization组织,可多个ArrayList<String[]> noteList = new ArrayList<String[]>();// 存note备注ArrayList<String[]> nicknameList = new ArrayList<String[]>();// 存Nickname昵称ArrayList<String[]> websiteList = new ArrayList<String[]>();// 存Website网站while (c.moveToNext()) {// 根据mimeType分类信息mimeType = c.getString(c.getColumnIndex(Data.MIMETYPE));if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {contentValue = MyUtils.getStringInContactCursor(c,PROJECTION_DISPLAYNAME_CONTACT);displayNameList.add(contentValue);} else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {// 每个contentValue存一类PROJECTION_PHONENUMBER_CONTACT数据contentValue = MyUtils.getStringInContactCursor(c,PROJECTION_PHONENUMBER_CONTACT);phoneList.add(contentValue);} else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {contentValue = MyUtils.getStringInContactCursor(c,PROJECTION_EAMIL_CONTACT);emailList.add(contentValue);} else if (Im.CONTENT_ITEM_TYPE.equals(mimeType)) {contentValue = MyUtils.getStringInContactCursor(c,PROJECTION_IM_CONTACT);imList.add(contentValue);} else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType)) {contentValue = MyUtils.getStringInContactCursor(c,PROJECTION_ADDRESS_CONTACT);postalList.add(contentValue);} else if (Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {contentValue = MyUtils.getStringInContactCursor(c,PROJECTION_ORGANIZATION_CONTACT);organizationList.add(contentValue);} else if (Note.CONTENT_ITEM_TYPE.equals(mimeType)) {contentValue = MyUtils.getStringInContactCursor(c,PROJECTION_NOTES_CONTACT);noteList.add(contentValue);} else if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) {contentValue = MyUtils.getStringInContactCursor(c,PROJECTION_NICKNAMES_CONTACT);nicknameList.add(contentValue);} else if (Website.CONTENT_ITEM_TYPE.equals(mimeType)) {contentValue = MyUtils.getStringInContactCursor(c,PROJECTION_WEBSITES_CONTACT);websiteList.add(contentValue);}}c.close();// logMyUtils.logContactsDetails("displayName",PROJECTION_DISPLAYNAME_CONTACT, displayNameList);MyUtils.logContactsDetails("phoneNumber",PROJECTION_PHONENUMBER_CONTACT, phoneList);MyUtils.logContactsDetails("Email", PROJECTION_EAMIL_CONTACT,emailList);MyUtils.logContactsDetails("IM", PROJECTION_IM_CONTACT, imList);MyUtils.logContactsDetails("Address", PROJECTION_ADDRESS_CONTACT,postalList);MyUtils.logContactsDetails("Organization",PROJECTION_ORGANIZATION_CONTACT, organizationList);MyUtils.logContactsDetails("Note", PROJECTION_NOTES_CONTACT, noteList);MyUtils.logContactsDetails("NickName", PROJECTION_NICKNAMES_CONTACT,nicknameList);MyUtils.logContactsDetails("WebSit", PROJECTION_WEBSITES_CONTACT,websiteList);}

用到的两个方法:

public static String[] getStringInContactCursor(Cursor c,String[] projection) {String[] contentValue = new String[projection.length];for (int i = 0; i < contentValue.length; i++) {String value = c.getString(c.getColumnIndex(projection[i]));if (value == null) {contentValue[i] = "";} else {contentValue[i] = value;}}return contentValue;}public static void logContactsDetails(String title, String[] projection,ArrayList<String[]> data) {Log.e("wu0wu", "--------" + title + "--------");for (int i = 0; i < data.size(); i++) {for (int j = 0; j < data.get(i).length; j++) {Log.e("wu0wu", projection[j] + "=" + data.get(i)[j]);}}}

3.3 新建联系人

接口方法:

/*** 新建联系人的接口* * @param String*            accountName,accountType 为账号名账号类型,一般为NULL* @throws RemoteException* @throws OperationApplicationException*/public static String _insertContact(ContentResolver cr, String accountName,String accountType, String displayName, ArrayList<String[]> phone,ArrayList<String[]> email, ArrayList<String[]> im,ArrayList<String[]> address, ArrayList<String[]> organization,ArrayList<String[]> notes, ArrayList<String[]> nickname,ArrayList<String[]> website) throws RemoteException,OperationApplicationException {ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();String rawId = "";long rawContactId = insertRawContact(cr, accountName, accountType);rawId = Long.toString(rawContactId);if (displayName != null) {insertContactDisplayname(ops, StructuredName.CONTENT_ITEM_TYPE,rawId, displayName);}if (phone != null) {for (int j = 0; j < phone.size(); j++) {String[] item = phone.get(j);insertItemToContact(ops, Phone.CONTENT_ITEM_TYPE, rawId,PROJECTION_PHONENUMBER_CONTACT, item);}}if (email != null) {for (int j = 0; j < email.size(); j++) {String[] item = email.get(j);insertItemToContact(ops, Email.CONTENT_ITEM_TYPE, rawId,PROJECTION_EAMIL_CONTACT, item);}}if (im != null) {for (int j = 0; j < im.size(); j++) {String[] item = im.get(j);insertItemToContact(ops, Im.CONTENT_ITEM_TYPE, rawId,PROJECTION_IM_CONTACT, item);}}if (address != null) {for (int j = 0; j < address.size(); j++) {String[] item = address.get(j);insertItemToContact(ops, StructuredPostal.CONTENT_ITEM_TYPE,rawId, PROJECTION_ADDRESS_CONTACT, item);}}if (organization != null) {for (int j = 0; j < organization.size(); j++) {String[] item = organization.get(j);insertItemToContact(ops, Organization.CONTENT_ITEM_TYPE, rawId,PROJECTION_ORGANIZATION_CONTACT, item);}}if (notes != null) {for (int j = 0; j < notes.size(); j++) {String[] item = notes.get(j);insertItemToContact(ops, Note.CONTENT_ITEM_TYPE, rawId,PROJECTION_NOTES_CONTACT, item);}}if (nickname != null) {for (int j = 0; j < nickname.size(); j++) {String[] item = nickname.get(j);insertItemToContact(ops, Nickname.CONTENT_ITEM_TYPE, rawId,PROJECTION_NICKNAMES_CONTACT, item);}}if (website != null) {for (int j = 0; j < website.size(); j++) {String[] item = website.get(j);insertItemToContact(ops, Website.CONTENT_ITEM_TYPE, rawId,PROJECTION_WEBSITES_CONTACT, item);}}cr.applyBatch(ContactsContract.AUTHORITY, ops);return rawId;}/** 通过往ROWCONTACT里插入数据,获得rawId* * @param cr* * @param accountName 一般为NULL* * @param accountType 一般为NULL* * @return*/private static long insertRawContact(ContentResolver cr,String accountName, String accountType) {ContentValues values = new ContentValues();values.put(RawContacts.ACCOUNT_NAME, accountName);values.put(RawContacts.ACCOUNT_TYPE, accountType);// values.put(Contacts.DISPLAY_NAME, displayName);Uri rawContactUri = cr.insert(RawContacts.CONTENT_URI, values);long rawContactId = ContentUris.parseId(rawContactUri);return rawContactId;}private static void insertContactDisplayname(ArrayList<ContentProviderOperation> ops, String mimeType,String rawContactId, String displayName) throws RemoteException,OperationApplicationException {ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI).withValue(Data.MIMETYPE, mimeType).withValue(Data.RAW_CONTACT_ID,rawContactId).withValue(StructuredName.DISPLAY_NAME,displayName).build());}private static void insertItemToContact(ArrayList<ContentProviderOperation> ops, String mimeType,String rawContactId, String[] PROJECTION_CONTACT, String[] item)throws RemoteException, OperationApplicationException {// ContentValues values = new ContentValues();// values.put(Data.RAW_CONTACT_ID, rawContactId);// values.put(Data.MIMETYPE, mimeType);// for (int i = 0; i < PROJECTION_CONTACT.length; i++) {// values.put(PROJECTION_CONTACT[i], item[i]);// }// Uri dataUri = cr.insert(Data.CONTENT_URI, values);Builder builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);builder.withYieldAllowed(true);builder.withValue(Data.RAW_CONTACT_ID, rawContactId);builder.withValue(Data.MIMETYPE, mimeType);for (int i = 0; i < PROJECTION_CONTACT.length; i++) {builder.withValue(PROJECTION_CONTACT[i], item[i]);}ops.add(builder.build());}

Android 2.0中电话本contact的读写操作(增删改查)相关推荐

  1. Android 2.0中电话本contact的读写操作(增删改查一)

    一.前言 1.1 Android的电话本的机制. Android的电话本通过contentProvider封装好的.我们只要通过sdk提供的Uri和字段来对其进行增.删.改.查. 1.2 权限 < ...

  2. Android 数据库(SQLite)【简介、创建、使用(增删改查、事务、实战演练)、数据显示控件(ListView、Adapter、实战演练-绿豆通讯录)】

    目   录 (壹)SQLite数据库简介 (贰)数据库的创建 (叁)数据库的使用 3.1.SQlite的基本操作 3.1.1.添加数据 3.1.2.修改数据 3.1.3.查询数据 3.1.4.删除数据 ...

  3. android绿豆通讯录xml,Android 数据库(SQLite)【简介、创建、使用(增删改查、事务、实战演练)、数据显示控件(ListView、Adapter、实战演练)】...

    目   录 (壹)SQLite数据库简介 (贰)数据库的创建 (叁)数据库的使用 3.1.SQlite的基本操作 3.1.1.添加数据 3.1.2.修改数据 3.1.3.查询数据 3.1.4.删除数据 ...

  4. Android 绿豆通讯录【SQLite数据库---数据库(增删改查、展示数据)】

    前情提要:Android 数据库(SQLite) [简介.创建.使用(增删改查.事务.实战演练).数据显示控件(ListView.Adapter.实战演练-绿豆通讯录)] https://blog.c ...

  5. Android 绿豆通讯录【 SQLite数据库(增删改查、展示数据) + ListView数据展示控件(展示所有数据) 】

    前情提要:Android 数据库(SQLite) [简介.创建.使用(增删改查.事务.实战演练).数据显示控件(ListView.Adapter.实战演练-绿豆通讯录)] https://blog.c ...

  6. mongodb android,Android编程连接MongoDB及增删改查等基本操作示例

    本文实例讲述了Android编程连接MongoDB及增删改查等基本操作.分享给大家供大家参考,具体如下: MongoDB简介 Mongodb,分布式文档存储数据库,由C++语言编写,旨在为WEB应用提 ...

  7. android绿豆通讯录xml,Android 绿豆通讯录【SQLite数据库---数据库(增删改查、展示数据)】...

    前情提要:Android 数据库(SQLite) [简介.创建.使用(增删改查.事务.实战演练).数据显示控件(ListView.Adapter.实战演练-绿豆通讯录)] https://blog.c ...

  8. Android整合SQLite数据库进行基本的增删改查

    简言 使用Android整合SQLite数据库进行数据存储,大致可以划分为三步: ①继承 SQLiteOpenHelper,创建数据库 ②继承 ContentProvider 类,重写方法 ③在清单文 ...

  9. android连接sqlite进行简单的增删改查和事务管理

    为什么80%的码农都做不了架构师?>>>    Android连接数据库sqlite并进行简单的表创建和增删改查功能参考代码,使用Android单元测试进行验证,首先新建项目进行配置 ...

最新文章

  1. 【优秀作业】蚁群优化算法
  2. CCNP ONT LAB之PQ WFQ
  3. Hibernate学习5—Hibernate操作对象
  4. 直播预告 | AAAI 2022论文解读:对称的语义感知的妆容迁移与移除网络
  5. 瀑布流 颜色随机 加载滚动
  6. nginx汇总(z)
  7. Android之FLAG_ACTIVITY_TASK_ON_HOME
  8. 你单身,其实是个科学问题……
  9. windows配置gvim高效率编程(cc++)带自动补全代码
  10. 问题解决 xenapp6/6.5发布资源管理器explorer应用不能打开 一闪而过
  11. 什么是OPTEE-OS
  12. python3携程多任务_python3之携程yield及greenlet
  13. idea javafx添加maven_IntelliJ IDEA使用之JavaFX
  14. 单词吸血鬼源代码 二叉树操作
  15. 工商银行近20年实时大数据平台建设历程
  16. Linux软件包管理工具-yum
  17. PHP写入txt文件换行
  18. 小学五年级计算机教学论文,小学五年级数学教学论文
  19. Java的String类中提到的代码点,代码单元到底是什么?
  20. 100部电影,100种人生,你看过几部?

热门文章

  1. 交友APP诈骗黑幕:有组织手把手传授引诱充值套路
  2. 2019-7-25 考试总结
  3. 最新最牛 功能最多的四角号码在线查询
  4. PHP美团外卖开放平台开发记录,IM在线通讯token获取和消息解密!By勤勤学长
  5. rocm平台_TensorFlow通过AMD GPU加速(ROCm/Ubuntu 18.04)
  6. yacc学习笔记(四)带符号表的计算器程序
  7. windows如何设置定时关机
  8. 物品抠图怎么更换背景?快来get这个方法
  9. Python-发送邮件和短信
  10. Vue(27)vue-codemirror实现在线代码编译器