自Android 2.0(API Level 5)开始,Android平台采用了改进后的Contacts API- ContactsContract,用于管理和集成来自多账户和多数据来源的联系人信息。新的联系人API在android.provider.ContactsContract及相关的类来定义,老的API已经废弃,但仍然可以使用。

  1. Contact API的结构和使用方法

和老的API有所不同的是,在新的Contacts API中,联系人数据被安排三个主要的表中:contacts, raw contacts和 data。这种新的结构可以使系统更加容易储存和管理从多个数据源得到的特定的联系人数据。结构如下图所示:

(图片来源于:developer.android.com)

1) Data表:储存所有与RawContract相关具体的信息。表的每一条记录对应一个特定信息,如:名字、电话,email地址, 头像和组信息等。每一记录通过一个mimetype_id字段来表明该行所记录的数据类型。例如,如果row的数据类型是Phone.CONTENT_ITEM_TYPE,那么第一个字段应该保存电话号码,如果数据类型为Email.CONTENT_ITEM_TYPE,那么这一记录的字段应该保存邮件地址。

Data表的字段主要有:

mimetype_id表示该行存储的信息的类型
raw_contact_id表示该行所属的RawContact
is_primary多个data数据组成一个raw contact,该字段表示此data是否是其所属的raw contact的主data,即其display name会作为raw contact的display name
is_super_primary该data是否是其所属的contact的主data,如果is_super_primary为1则is_primary一定为1
data1~data1515个数据字段,对于不同类型的信息,表示不同的含义,ContactsContract.CommomDataKinds类中定义了与常用的数据类型相对应的一些类,这些类中分别定义了相应数据类型中这些字段表示的含义。一般data1表是主信息(如电话,Email地址等),data2表示副信息,data15表示Blob数据。
data_sync1~data_sync4sync_adapter要用的字段(sync_adapter用于数据的同步,比如你手机中的Gmail帐户与Google服务器的同步)。
data_version数据的版本,用于数据的同步。

 

2)RawContact表中的一行存储Data表中一些数据行的集合及一些其他的信息,表示一个联系人某一特定帐户的信息,比如Facebook或Exchange的一个联系人。 
当插入一个raw contact或当一个raw contact所属的一个data改变时,系统会检查这个raw contact跟其他的raw contact是否可以匹配(比如如果两个raw contact的data包含相同的电话号码或名字),如果匹配他们就会被综合到一起,也就是说他们会属于同一个cantact,表现为在RawContact表中他们引用的cantact_id是一样的。
联系人姓名、组织、电话号码、Email或昵称的改变会引发raw contact的重新聚合。有两个方法控制聚合的行为Aggregaton Mode与ContactsContract.AggregationExceptions。

Aggregaton Mode:
RawContact表中有一个字段aggregation_mode,通过向特定raw contact行中插入这个字段可以修改系统对这个raw contact的聚合行为,其允许的值如下:AGGREGATION_MODE_DEFAULT:正常模式,允许自动聚合;
AGGREGATION_MODE_DISABLE:不允许聚合;
AGGREGATION_MODE_SUSPENDED:当一个raw contact的aggregation mode修改为suspended时,如果其已是一个已聚合的contact的一部分,那么它仍会保持与原来聚合到一起的raw contact的关系,即使它已改变不再跟其他raw contact匹配。AGGREGATIONEXCEPTIONS:

在数据库中存在一个表:agg_exceptions。通过字段raw_contact_id1、raw_contact_id2、mode存储两个raw contact聚合的方法,系统定义的聚合行为有3个:
TYPE_AUTOMATIC=0  由系统决定聚合行为,默认值。
TYPE_KEEP_SEPARATE=2  不聚合
TYPE_KEEP_TOGETHER=1  聚合

3) Contact表中的一行表示一个联系人,它是RawContact表中的一行或多行的数据的组合,这些RawContact表中的行表示同一个人的不同的帐户信息。Contact中的数据由系统组合RawContact表中的数据自动生成。不可以直接向这个表中插入数据,当一个raw contact被插入的时候,系统会首先查找Contact表看是否有记录跟插入的raw contact表示同一个人,如果找到了,则把找到的这个contact的_ID插入raw contact记录的CONTACT_ID字段,如果没有找到,则系统自动插入一个Contact记录并把它的_ID插入新插入的raw contact的CONTACT_ID列。

Contact表中只有TIMES_CONTACTED、LAST_TIME_CONTACTED、STARRED、CUSTOM_RINGTONE、SENE_TO_VOICEMAIL列可更改,这些列的更改会导致相应的raw contact被更改。

数据删除
    Contacts文档说:
    Be careful with deleting Contacts! Deleting an aggregate contact deletes all constituent raw contacts.
    The corresponding sync adapters will notice the deletions of their respective raw contacts 
    and remove them from their back end storage.
    删除一个Contacts,会把它所包含所有raw contacts都删除掉。
    但是用下面语句居然删除不了任何Contacts.
    getContentResolver().delete(Contacts.CONTENT_URI, null, null);
    不过在删除Contacts的所有raw contacts后,Contacts也被删除了。

如果需要读取一个联系人的信息用CONTENT_LOOKUP_URI代替CONTENT_URI;

如果需要通过电话号码查找一个联系人,用PhoneLookup.CONTENT_FIILTER_URI,这个URI为这个目的进行了优化;

如果需要通过部分名字的匹配查找,用CONTENT_FILTER_URI;

如果需要通过email,address等信息查找,查找表ContactsContract.Data,结果包含contact ID,名字...

android.provider.ontactsContract.Data类

其定义如下:


 

 public final static class Data implements DataColumnsWithJoins {
private Data() {}
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "data");
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/data";
//This flag is useful (currently) only for vCard exporter in Contacts app
public static final String FOR_EXPORT_ONLY = "for_export_only";
/*Build a CONTENT_LOOKUP_URI style Uri for the parent ContactsContract.Contacts entry of the given ContactsContract.Data entry.*/
public static Uri getContactLookupUri(ContentResolver resolver, Uri dataUri) {...}
}


 

Data类定义了CONTENT_URI及CONTENT_TYPE,主要是继承了DataColumnsWithJoins接口中的字段。DataColumnsWithJoins定义如下:

protected interface DataColumnsWithJoins extends BaseColumns, DataColumns, StatusColumns,
RawContactsColumns, ContactsColumns, ContactNameColumns, ContactOptionsColumns,
ContactStatusColumns {
}

该接口只是综合了一些接口,其中:

BaseColumns定义了_ID与_COUNT字段,ContentProvider查询中都要用到的字段。

DataColumns定义了与Data表中字段一一对应的常量

RawContactsColumns, ContactsColumns, ContactNameColumns, ContactOptionsColumns表示RawContact与Contact中的一些字段,定义到此类中以方便访问。

由于联系人的信息都是按类别存储到了这个Data表中,所以我们要查找联系人的信息只需要查这个表。Data类中的Data.CONTACT_ID与Data.RAW_CONTACT_ID分别表示该表项对应的联系人在Contact与RawContract表中的ID,我们只需要知道某一个联系人的contactId或rawContractId,并根据其查找的数据的类型就可以查到相应类型的信息。

Cursor c = getContentResolver().query(Data.CONTENT_URI,
new String[] {Data._ID, Phone.NUMBER, Phone.TYPE, Phone.LABEL},
Data.CONTACT_ID + "=?" + " AND "
+ Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'",
new String[] {String.valueOf(contactId)}, null);

以上代码根据联系人的contractId,并通过设置其MIMETYPE为Phone.CONTENT_ITEM_TYPE查到了该联系人的电话号码,把Data.CONTACT_ID换为Data.RAW_CONTACT_ID即可查找相应rawContactId对应的电话号码。其中用到了Phone.CONTENT_ITEM_TYPE,这是什么呢?

CommonDataKinds类

2 0

共收到0条回复

加入小组与大家一起讨论吧