[通讯录] android通讯录数据库表解析和添加,访问通讯录

实际应用,“通讯录” 数据读取、添加联系人信息

      ** 查看通讯录数据库:

           首先启动模拟器、再打开 “File Explorer” 视图,

           依次展开:data -- data -- com.android.providers.contacts(注意和 com.android.contacts 区分) -- databases,如图:

           


           点击右上角的导出图标,如图:

            

           将数据库文件导出到电脑磁盘上。

           然后,你需要拥有一个能打开 SQLite 数据库的工具。例如我用的 SQLite Expert Personal。可以在网上搜索下载。

           打开数据库后,就比较纠结了,需要观察表结构。如果确实看得比较纠结,干脆甩开,以免打击学习激情。

           或者一狠心,自己写一个管理联系人的程序,弄个自己的通讯录数据库。

          raw_contacts 表: 联系人 ID

           data表 : 联系人的数据表。通过raw_contacts_id 与 raw_contacts 表联系

                          存放的联系人信息如:手机号、姓名、Email 等。

                          联系人的每一项数据,都会在 data 表产生一条记录。例如,记录手机号的是单独一条记录,记录 Email 的是单独一条记录。并且都用 data1 字段来存放。

                          也就是说,联系人的所有重要信息,都以单独记录的方式,保存在这张表里的 data1字段。用 raw_contacts_id 来描述信息所属的联系人。用 mimitype_id 来描述 data1 字段存储的数据类型(是 Email 数据么?手机号数据么?座机数据么?)。


                          假如data1要存放的数据是 “由几个数据组合起来的” ,例如:姓名中的 FirstName 和 LastName。

                          那么就往后存到 data2、data3 里面。组合起来的完整姓名存放在 data1

                           区分这条数据到底是短信数据、电话数据、Emai等,则是依靠 mimitype_id 字段来区分

                           mimitype_id 其实是 mimitypes 的外键。观察此表得知:1 表示 email、6 表示姓名、5 表示电话号码。

                           data2:也用来说明 data1。例如,如果是此记录记录的数据是电话号码,那么若是住宅电话,此字段为1;手机号码为2;单位电话为3......

                          这些字段的意义很重要,建议读者花10分钟大致看一眼(强烈建议不要花太多时间去研究这个,意义不大),再结合后面的程序,相信会很容易理解。

                          既然知道了数据存放的方式了,知道它们的字段的名称了,表名也知道了。(当然,编程时我们尽量使用 Android 提供的常量。否则也许今天写的程序,用到了某某字段,睡一觉起来 Android 升完级,不认了。)


                          好了,sql 语句的几个要素都成立了。要存取联系人好了做吧。


                          当然啦,这个过程要通过 “联系人” 对外提供的接口来完成,毕竟这个程序是人家的,这个表也是人家的,我们不能直接访问第三方程序的数据库。要提供这个接口的方式可多了,ContentProvider 无疑是最佳的选择。

                          说穿了,其实就是我们在我们的程序中,组拼出我们需要的 sql 语句,通过 ContentProvider 通信机制,将 sql 语句送到 “联系人”程序去执行而已。并不神奇和复杂,不是么?                        


              calls表:存放的呼叫记录。在《Android--删除某联系人的通话记录》中需要操作它

           

    源码在:

       ${对应版本SDK源码目录}/ContactsProvider/src/com/android/providers/contacts/ContactsProvider2.java

    可以通过查看源码,获知 Uri

            ...

            matcher.addURI(ContactsContract.AUTHORITY, "data", DATA);

            matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID);

            matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES);

            matcher.addURI(ContactsContract.AUTHORITY, "data/phones/#", PHONES_ID);

            matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter", PHONES_FILTER);

            matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER);

            matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS);

            matcher.addURI(ContactsContract.AUTHORITY, "data/emails/#", EMAILS_ID);

            matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup/*", EMAILS_LOOKUP);

            matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter", EMAILS_FILTER);

            matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER);

            matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS);

            matcher.addURI(ContactsContract.AUTHORITY, "data/postals/#", POSTALS_ID);

            ...

            要按照电话号码获取某一个联系人可以使用:

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


** 示例代码:(上代码之前,最好的建议是:边看这个例子,边打开数据库和源码瞅瞅,对 ContentProvider 的理解会深入很多)

     1. AndroidManifest.xml 加入权限

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

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


      2.

  1. package wjh.android.contact;
  2. import java.util.ArrayList;
  3. import android.content.ContentProviderOperation;
  4. import android.content.ContentProviderResult;
  5. import android.content.ContentResolver;
  6. import android.content.ContentUris;
  7. import android.content.ContentValues;
  8. import android.database.Cursor;
  9. import android.net.Uri;
  10. import android.provider.ContactsContract;
  11. import android.provider.ContactsContract.RawContacts;
  12. import android.provider.ContactsContract.CommonDataKinds.Email;
  13. import android.provider.ContactsContract.CommonDataKinds.Phone;
  14. import android.provider.ContactsContract.CommonDataKinds.StructuredName;
  15. import android.provider.ContactsContract.Contacts.Data;
  16. import android.test.AndroidTestCase;
  17. import android.util.Log;
  18. /**
  19. * 通讯录操作示例
  20. *
  21. */
  22. public class ContactTest extends AndroidTestCase {
  23.   private static final String TAG = "ContactTest";
  24.   /**
  25.    * 获取通讯录中所有的联系人
  26.    */
  27.   public void testGetContacts() throws Throwable {
  28.     ContentResolver contentResolver = this.getContext().getContentResolver();
  29.     String uriStr = "content://com.android.contacts/contacts";
  30.     Uri uri = Uri.parse(uriStr);
  31.     Cursor cursor = contentResolver.query(uri, null, null, null, null);
  32.     // 遍历联系人
  33.     while (cursor.moveToNext()) {
  34.       // 联系人 ID
  35.       int contactId = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts._ID));
  36.       // 联系人显示名称
  37.       String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
  38.       
  39.       // 联系人电话号码需要对另一个表进行查询,所以用到另一个 uri:content://com.android.contacts/data/phones
  40.       Cursor phones = getContext().getContentResolver().query(
  41.                                   ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
  42.                                   null,
  43.                                   ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = "   // 根据上一步获取的联系人 id 来查询
  44.                                                        + contactId, null, null);   
  45.       String phone = "";
  46.       while (phones.moveToNext()) {
  47.                                 // "data1"字段,所以此处也可以直接写 "data1",但不推荐
  48.         phone = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
  49.       }
  50.       
  51.       // 再查询 Email。uri 为 : content://com.android.contacts/data/emails
  52.       Cursor emails = getContext().getContentResolver().query(
  53.                                  ContactsContract.CommonDataKinds.Email.CONTENT_URI,
  54.                                  null,
  55.                                  ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = "
  56.                                                       + contactId, null, null);
  57.       while (emails.moveToNext()) {
  58.                                 /* 一样是 "data1" 字段。现在明白了吧?一个联系人的信息,其实被分成了好几条记录来保存,data1分别保存了各种重要的信息。
  59.                                  * 是时候参照打开数据库我前面所说,去瞄一眼它的表结构了!
  60.                                  */
  61.         String emailAddress = emails.getString(emails.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
  62.         Log.i("RongActivity", "emailAddress=" + emailAddress);
  63.       }
  64.       emails.close();
  65.       Log.i(TAG, "Contact [contactId= "+ contactId +"name=" + name + ", phone=" + phone + "]");
  66.     }
  67.   }
  68.   
  69.   /**
  70.    * 首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获取系统返回的rawContactId
  71.    * 这时后面插入data表的依据,只有执行空值插入,才能使插入的联系人在通讯录里面可见
  72.    */
  73.   public void testInsert() {
  74.     ContentValues values = new ContentValues();
  75.     //首先向RawContacts.CONTENT_URI执行一个空值插入(raw_contacts 表), 为了获取生成的联系人 ID
  76.     Uri rawContactUri = this.getContext().getContentResolver().insert(RawContacts.CONTENT_URI, values);
  77.    
  78.     //然后获取系统返回的rawContactId , 就是新加入的这个联系人的 ID
  79.     long rawContactId = ContentUris.parseId(rawContactUri);
  80.    
  81.      /* Andorid 中,将联系人的姓名、电话、Email
  82.       * 分别存放在 data 表的同一个字段的三条记录当中
  83.       * 因此要  Insert 三次 */   
  84.    
  85.     //往data表入姓名数据
  86.     values.clear();
  87.    
  88.     // raw_contacts_id 字段,是 raw_contacts表id 的外键,用于说明此记录属于哪一个联系人
  89.     values.put(Data.RAW_CONTACT_ID, rawContactId);
  90.    
  91.     // mimitype_id 字段,用于描述此数据的类型,电话号码?Email?....
  92.     values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);   // 注意查看第二个参数的常量值
  93.    
  94.     values.put(StructuredName.GIVEN_NAME, "文白菜");   // 这个名字真好听
  95.     this.getContext().getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI, values);
  96.    
  97.     //往data表入电话数据
  98.     values.clear();
  99.     values.put(Data.RAW_CONTACT_ID, rawContactId);
  100.    
  101.     values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
  102.     values.put(Phone.NUMBER, "15101689230");
  103.     values.put(Phone.TYPE, Phone.TYPE_MOBILE);
  104.     this.getContext().getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI, values);
  105.    
  106.     //往data表入Email数据
  107.     values.clear();
  108.     values.put(Data.RAW_CONTACT_ID, rawContactId);
  109.     values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
  110.     values.put(Email.DATA, "[email protected]");
  111.     values.put(Email.TYPE, Email.TYPE_WORK);
  112.     this.getContext().getContentResolver().insert(android.provider.ContactsContract.Data.CONTENT_URI, values);
  113.   }
  114.   /**
  115.    * 在同一个事务当中保存联系人
  116.    */
  117.   public void testSave() throws Throwable{
  118.     //文档位置:reference/android/provider/ContactsContract.RawContacts.html
  119.     ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
  120.    
  121.     int rawContactInsertIndex = ops.size();
  122.     ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
  123.                                   .withValue(RawContacts.ACCOUNT_TYPE, null)
  124.                                   .withValue(RawContacts.ACCOUNT_NAME, null)
  125.                                   .build());
  126.     //文档位置:reference/android/provider/ContactsContract.Data.html
  127.     ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
  128.                                   .withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
  129.                                   .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
  130.                                   .withValue(StructuredName.GIVEN_NAME, "文萝卜")
  131.                                   .build());
  132.     // 更新手机号码:Data.RAW_CONTACT_ID 获取上一条语句插入联系人时产生的 ID
  133.     ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
  134.                                   .withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
  135.                                               .withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
  136.                                               .withValue(Phone.NUMBER, "15101689231")  // "data1"
  137.                                               .withValue(Phone.TYPE, Phone.TYPE_MOBILE)
  138.                                               .withValue(Phone.LABEL, "手机号")
  139.                                               .build());
  140.     ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
  141.                                   .withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
  142.                                               .withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE)
  143.                                               .withValue(Email.DATA, "[email protected]")
  144.                                               .withValue(Email.TYPE, Email.TYPE_WORK)
  145.                                               .build());
  146.    
  147.     // 批量插入 -- 在同一个事务当中
  148.     ContentProviderResult[] results = this.getContext().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
  149.     for(ContentProviderResult result : results){
  150.       Log.i(TAG, result.uri.toString());
  151.     }
  152.   }
  153. }
普通浏览 复制代码 保存代码 打印代码
  1. package wjh.android.contact ;
  2. import java.util.ArrayList ;
  3. import android.content.ContentProviderOperation ;
  4. import android.content.ContentProviderResult ;
  5. import android.content.ContentResolver ;
  6. import android.content.ContentUris ;
  7. import android.content.ContentValues ;
  8. import android.database.Cursor ;
  9. import android.net.Uri ;
  10. import android.provider.ContactsContract ;
  11. import android.provider.ContactsContract.RawContacts ;
  12. import android.provider.ContactsContract.CommonDataKinds.Email ;
  13. import android.provider.ContactsContract.CommonDataKinds.Phone ;
  14. import android.provider.ContactsContract.CommonDataKinds.StructuredName ;
  15. import android.provider.ContactsContract.Contacts. Data ;
  16. import android.test.AndroidTestCase ;
  17. import android.util.Log ;
  18. /**
  19.  * 通讯录操作示例
  20.  *
  21.  */
  22. public  class ContactTest extends AndroidTestCase {
  23.    private  static final String TAG =  "ContactTest" ;
  24.    /**
  25.    * 获取通讯录中所有的联系人
  26.    */
  27.    public  void testGetContacts ( ) throws Throwable {
  28.     ContentResolver contentResolver =  this.getContext ( ).getContentResolver ( ) ;
  29.     String uriStr =  "content://com.android.contacts/contacts" ;
  30.     Uri uri = Uri.parse (uriStr ) ;
  31.     Cursor cursor = contentResolver.query (uri,  nullnullnullnull ) ;
  32.      // 遍历联系人
  33.      while  (cursor.moveToNext ( ) ) {
  34.        // 联系人 ID
  35.        int contactId = cursor.getInt (cursor.getColumnIndex (ContactsContract.Contacts._ID ) ) ;
  36.        // 联系人显示名称
  37.       String name = cursor.getString (cursor.getColumnIndex (ContactsContract.Contacts.DISPLAY_NAME ) ) ;
  38.       
  39.        // 联系人电话号码需要对另一个表进行查询,所以用到另一个 uri:content://com.android.contacts/data/phones 
  40.       Cursor phones = getContext ( ).getContentResolver ( ).query (
  41.                                   ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
  42.                                    null,
  43.                                   ContactsContract.CommonDataKinds.Phone.CONTACT_ID +  " = "    // 根据上一步获取的联系人 id 来查询
  44.                                                        + contactId,  nullnull ) ;   
  45.       String phone =  "" ;
  46.        while  (phones.moveToNext ( ) ) {
  47.                                  // "data1"字段,所以此处也可以直接写 "data1",但不推荐
  48.         phone = phones.getString (phones.getColumnIndex (ContactsContract.CommonDataKinds.Phone.NUMBER ) ) ;
  49.       }
  50.       
  51.        // 再查询 Email。uri 为 : content://com.android.contacts/data/emails 
  52.       Cursor emails = getContext ( ).getContentResolver ( ).query (
  53.                                  ContactsContract.CommonDataKinds.Email.CONTENT_URI,
  54.                                   null,
  55.                                  ContactsContract.CommonDataKinds.Email.CONTACT_ID +  " = "
  56.                                                       + contactId,  nullnull ) ;
  57.        while  (emails.moveToNext ( ) ) {
  58.                                  /* 一样是 "data1" 字段。现在明白了吧?一个联系人的信息,其实被分成了好几条记录来保存,data1分别保存了各种重要的信息。
  59.                                  * 是时候参照打开数据库我前面所说,去瞄一眼它的表结构了!
  60.                                  */
  61.         String emailAddress = emails.getString (emails.getColumnIndex (ContactsContract.CommonDataKinds.Email.DATA ) ) ;
  62.         Log.i ( "RongActivity""emailAddress=" + emailAddress ) ;
  63.       }
  64.       emails.close ( ) ;
  65.       Log.i (TAG,  "Contact [contactId= "+ contactId + "name=" + name +  ", phone=" + phone +  "]" ) ;
  66.     }
  67.   }
  68.   
  69.    /**
  70.    * 首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获取系统返回的rawContactId 
  71.    * 这时后面插入data表的依据,只有执行空值插入,才能使插入的联系人在通讯录里面可见
  72.    */
  73.    public  void testInsert ( ) {
  74.     ContentValues values =  new ContentValues ( ) ;
  75.      //首先向RawContacts.CONTENT_URI执行一个空值插入(raw_contacts 表), 为了获取生成的联系人 ID
  76.     Uri rawContactUri =  this.getContext ( ).getContentResolver ( ).insert (RawContacts.CONTENT_URI, values ) ;
  77.     
  78.      //然后获取系统返回的rawContactId , 就是新加入的这个联系人的 ID
  79.      long rawContactId = ContentUris.parseId (rawContactUri ) ;
  80.     
  81.       /* Andorid 中,将联系人的姓名、电话、Email 
  82.       * 分别存放在 data 表的同一个字段的三条记录当中
  83.       * 因此要  Insert 三次 */    
  84.     
  85.      //往data表入姓名数据
  86.     values.clear ( ) ;
  87.     
  88.      // raw_contacts_id 字段,是 raw_contacts表id 的外键,用于说明此记录属于哪一个联系人
  89.     values.put ( Data.RAW_CONTACT_ID, rawContactId ) ; 
  90.     
  91.      // mimitype_id 字段,用于描述此数据的类型,电话号码?Email?....
  92.     values.put ( Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE ) ;    // 注意查看第二个参数的常量值
  93.     
  94.     values.put (StructuredName.GIVEN_NAME,  "文白菜" ) ;    // 这个名字真好听
  95.      this.getContext ( ).getContentResolver ( ).insert (android.provider.ContactsContract. Data.CONTENT_URI, values ) ;
  96.     
  97.      //往data表入电话数据
  98.     values.clear ( ) ;
  99.     values.put ( Data.RAW_CONTACT_ID, rawContactId ) ;
  100.     
  101.     values.put ( Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE ) ; 
  102.     values.put (Phone.NUMBER,  "15101689230" ) ;
  103.     values.put (Phone.TYPE, Phone.TYPE_MOBILE ) ;
  104.      this.getContext ( ).getContentResolver ( ).insert (android.provider.ContactsContract. Data.CONTENT_URI, values ) ;
  105.     
  106.      //往data表入Email数据
  107.     values.clear ( ) ;
  108.     values.put ( Data.RAW_CONTACT_ID, rawContactId ) ;
  109.     values.put ( Data.MIMETYPE, Email.CONTENT_ITEM_TYPE ) ;
  110.     values.put (Email.DATA,  "[email protected]" ) ;
  111.     values.put (Email.TYPE, Email.TYPE_WORK ) ;
  112.      this.getContext ( ).getContentResolver ( ).insert (android.provider.ContactsContract. Data.CONTENT_URI, values ) ;
  113.   }
  114.    /**
  115.    * 在同一个事务当中保存联系人
  116.    */
  117.    public  void testSave ( ) throws Throwable{
  118.      //文档位置:reference/android/provider/ContactsContract.RawContacts.html
  119.     ArrayList<ContentProviderOperation> ops =  new ArrayList<ContentProviderOperation> ( ) ;
  120.     
  121.      int rawContactInsertIndex = ops.size ( ) ;
  122.     ops.add (ContentProviderOperation.newInsert (RawContacts.CONTENT_URI )
  123.                                   .withValue (RawContacts.ACCOUNT_TYPE,  null )
  124.                                   .withValue (RawContacts.ACCOUNT_NAME,  null )
  125.                                   .build ( ) ) ;
  126.      //文档位置:reference/android/provider/ContactsContract.Data.html
  127.     ops.add (ContentProviderOperation.newInsert (android.provider.ContactsContract. Data.CONTENT_URI )
  128.                                   .withValueBackReference ( Data.RAW_CONTACT_ID, rawContactInsertIndex )
  129.                                   .withValue ( Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE )
  130.                                   .withValue (StructuredName.GIVEN_NAME,  "文萝卜" )
  131.                                   .build ( ) ) ;
  132.      // 更新手机号码:Data.RAW_CONTACT_ID 获取上一条语句插入联系人时产生的 ID
  133.     ops.add (ContentProviderOperation.newInsert (android.provider.ContactsContract. Data.CONTENT_URI )
  134.                                   .withValueBackReference ( Data.RAW_CONTACT_ID, rawContactInsertIndex )
  135.                                               .withValue ( Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE )
  136.                                               .withValue (Phone.NUMBER,  "15101689231" )   // "data1"
  137.                                               .withValue (Phone.TYPE, Phone.TYPE_MOBILE )
  138.                                               .withValue (Phone.LABEL,  "手机号" )
  139.                                               .build ( ) ) ;
  140.     ops.add (ContentProviderOperation.newInsert (android.provider.ContactsContract. Data.CONTENT_URI )
  141.                                   .withValueBackReference ( Data.RAW_CONTACT_ID, rawContactInsertIndex )
  142.                                               .withValue ( Data.MIMETYPE, Email.CONTENT_ITEM_TYPE )
  143.                                               .withValue (Email.DATA,  "[email protected]" )
  144.                                               .withValue (Email.TYPE, Email.TYPE_WORK )
  145.                                               .build ( ) ) ;
  146.     
  147.      // 批量插入 -- 在同一个事务当中
  148.     ContentProviderResult [ ] results =  this.getContext ( ).getContentResolver ( ).applyBatch (ContactsContract.AUTHORITY, ops ) ;
  149.      for (ContentProviderResult result : results ){
  150.       Log.i (TAG, result.uri.toString ( ) ) ;
  151.     }
  152.   }
  153. }

你可能感兴趣的:(android,android,通讯录,联系人,电话)