Pro Android学习笔记(一六十):联系人API(3):联系人数据

文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处http://blog.csdn.net/flowingflying/以及作者@恺风Wei。

联系人信息

查看reference中android.provider.ContactsContract.CommonDataKinds可以知道该版本的Android API联系人中带有哪些信息。在API level 19中,我们看到有以下的信息:

Pro Android学习笔记(一六十):联系人API(3):联系人数据_第1张图片

而各个信息,例如Email,又有着他的结构,我们可以继续查看ContactsContract.CommondataKinds.Email。

Pro Android学习笔记(一六十):联系人API(3):联系人数据_第2张图片

联系人数据库

一个账号account拥有其自己的联系人,这些联系人称为raw contacts,具有自己的数据信息,例如email,phone号码,地址等。Android在people应用中提供了raw contacts的整合,不同账号的raw contact进行整合,只在列表中出现一次。

联系人信息存放在/data/data/com.android.providers.contacts/databases中。

Pro Android学习笔记(一六十):联系人API(3):联系人数据_第3张图片

在profile.db中存放的是personal profile账号的下属联系人。我们将contacts2.db和profile.db导出来,通过SQLiteManager看看里面的内容,也可以用SDK中的platform-tools/sqlite3.exe命令,具体的参见Pro Android学习笔记(五):了解Content Provider(上)。

sqlite> .schema raw_contacts;
sqlite> .tables
_sync_state               phone_lookup              view_data_usage_stat
_sync_state_metadata      photo_files               view_entities
accounts                  properties                view_groups
agg_exceptions            raw_contacts              view_raw_contacts
android_metadata          search_index              view_raw_entities
calls                     search_index_content      view_stream_items
contacts                  search_index_docsize      view_v1_contact_methods
data                      search_index_segdir       view_v1_extensions
data_usage_stat           search_index_segments     view_v1_group_membership
default_directory         search_index_stat         view_v1_groups
deleted_contacts          settings                  view_v1_organizations
directories               status_updates            view_v1_people
groups                    stream_item_photos        view_v1_phones
mimetypes                 stream_items              view_v1_photos
name_lookup               v1_settings               visible_contacts
nickname_lookup           view_contacts             voicemail_status
packages                  view_data

raw contacts

每个账号下面有raw contacts表格,记录各自的raw contacts信息。通过图形工具,我们来查看raw_contacts的定义:

Pro Android学习笔记(一六十):联系人API(3):联系人数据_第4张图片

CREATE TABLE raw_contacts (
    _id INTEGER PRIMARY KEY AUTOINCREMENT
    account_id INTEGER REFERENCES accounts(_id),表明raw contact属于哪个account,可以在accounts的表中,根据_id查到account_name和account_type。
    sourceid TEXT表明这个raw contact在这个account中是唯一的,例如account为Google email账号,这里是用户的email ID。如何组织管理账号以及里面联系人和手机制造商有关,这里也可能weiNull。
    raw_contact_is_read_only INTEGER NOT NULL DEFAULT 0,
    version INTEGER NOT NULL DEFAULT 1,
    dirty INTEGER NOT NULL DEFAULT 0,
    deleted INTEGER NOT NULL DEFAULT 0,
    contact_id INTEGER REFERENCES contacts(_id),
表格contacts中是整合的账号表,这里是对应整合表contacts中的_id。
    aggregation_mode INTEGER NOT NULL DEFAULT 0,
    aggregation_needed INTEGER NOT NULL DEFAULT 1,
    custom_ringtone TEXT,
    send_to_voicemail INTEGER NOT NULL DEFAULT 0,
    times_contacted INTEGER NOT NULL DEFAULT 0,
    last_time_contacted INTEGER,
    starred INTEGER NOT NULL DEFAULT 0,
    pinned INTEGER NOT NULL DEFAULT 2147483647,

    display_name TEXT,这是只读,有表格data中的的data列触发生成。
    display_name_alt TEXT,
    display_name_source INTEGER NOT NULL DEFAULT 0,
    phonetic_name TEXT,
    phonetic_name_style TEXT,
    sort_key TEXT COLLATE PHONEBOOK,
    phonebook_label TEXT,
    phonebook_bucket INTEGER,
    sort_key_alt TEXT COLLATE PHONEBOOK,
    phonebook_label_alt TEXT,
    phonebook_bucket_alt INTEGER,
    name_verified INTEGER NOT NULL DEFAULT 0,

    sync1 TEXT,  sync2 TEXT,  sync3 TEXT, sync4 TEXT )sync用于设备上contact与服务器之间的同步。

我们也可以在android.providers.ContactsContact.RawContact中查看相关信息。

使用SDK的定义可以特别在不同SDK版本表格出现列的增删改情况,仍可以安全地使用。但是SDK中看起来很复杂和繁琐,不容易理清,所以我们直接看表格定义。自开放式,我们将使用SDK里面的定义。

data表

在raw_contacts表格并没有存放contact的所有信息,例如电话号码、邮件等,是存放在data表中。

CREATE TABLE data (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
package_id INTEGER REFERENCES package(_id),
mimetype_id INTEGER REFERENCES mimetype(_id) NOT NULL,表明是哪个信息,例如名字、电话号码等等,mimetype也将决定信息存储data1~data15的含义 。
raw_contact_id INTEGER REFERENCES raw_contacts(_id) NOT NULL,data表和raw_contacts表之间相互索引。raw_contact_id是可以重复的,用于分别存放不同的信息。
is_read_only INTEGER NOT NULL DEFAULT 0,
is_primary INTEGER NOT NULL DEFAULT 0,
is_super_primary INTEGER NOT NULL DEFAULT 0,
data_version INTEGER NOT NULL DEFAULT 0,
data1 TEXT,data2 TEXT,data3 TEXT,data4 TEXT,data5 TEXT,data6 TEXT,data7 TEXT,data8 TEXT,data9 TEXT,data10 TEXT,data11 TEXT,data12 TEXT,data13 TEXT,data14 TEXT,data15 TEXT,
data_sync1 TEXT, data_sync2 TEXT, data_sync3 TEXT, data_sync4 TEXT )

我们看一个查询的结果:

Pro Android学习笔记(一六十):联系人API(3):联系人数据_第5张图片

下面是表mimetype的内容,通过data中的mime_type_id可以检索具体的类型。用表格来存储类型,而不是进行固化,这可以灵活地增加、删除和修改定义,是个好的设计。

Pro Android学习笔记(一六十):联系人API(3):联系人数据_第6张图片

data表的各列也可以查看ContactsContract.Data,具体的某个mimetype对应的data1~data15各标识什么,可以查阅ContactsContract.CommonDataKinds.*,例如ContactsContract.CommonDataKinds.Phone。

整合联系人:表contacts

在不同的账号下面可以会有相同的联系人,Android进行了整合,存放在可读表contacts中,raw_contacts和data表有trigger可以触发来填写或者修改contacts表的数据。

CREATE TABLE contacts (
    _id INTEGER PRIMARY KEY AUTOINCREMENT,
    name_raw_contact_id INTEGER REFERENCES raw_contacts(_id),
    photo_id INTEGER REFERENCES data(_id),  
    photo_file_id INTEGER REFERENCES photo_files(_id),
    custom_ringtone TEXT,
    send_to_voicemail INTEGER NOT NULL DEFAULT 0,
    times_contacted INTEGER NOT NULL DEFAULT 0,
    last_time_contacted INTEGER,
    starred INTEGER NOT NULL DEFAULT 0,
    has_phone_number INTEGER NOT NULL DEFAULT 0,
    has_valid_sip_account INTEGER NOT NULL DEFAULT 0,
    lookup TEXT, contacts表格数据是系统根据raw contacts的数据进行生成和修改,这个表的数据会根据raw contacts的变化而变化,采用 将_id代表某个联系人,并将之作为索引,在某些情况下并不合适,因此引入了lookup,lookup是进行过编码,含有account以及其下的raw_contact联系人ID,可将之作为生成LookUpURI进行查询,获取最新整合联合人的信息。我们在下一学习的小例子进行演示。
    status_update_id INTEGER REFERENCES data(_id))

Andriod如何判断是否可以进行判断。如果两个raw_contacts名字相同,或者first name和last name的顺序不同,但内容一致,或者是缩写或昵称(例如Bob和Robert);如果name只有first name或者last name,将查找其他属性,例如电话号码、邮件,如果其他属性也匹配,可以进行整合;如果raw contact没有name,那么将查询其他属性。

基于这些判断进行整合是可能出现误判的。在raw_contacts中aggregation_mode列,有三个值:AGGEREGATION_MODE_DEFAULT,AGGERGATION_MODE_DISABLED(禁止整合,如果已经整合,将从整合中分离出来,为其分配一个新的contact ID),以及AGGEREGATION_MODE_SUSPENDED(当属性变化是,并不整合到整合联系人中)。

视图:view_contacts

API并不直接暴露contacts表,而是通过视图view_contacts读取。当通过URI:ContactsContract.Contacts.CONTENT_URI来查询时,实际查询的是view_contacts。

CREATE VIEW view_contacts AS

SELECT contacts._id AS _id,
contacts.custom_ringtone AS custom_ringtone,
name_raw_contact.display_name_source AS display_name_source,
name_raw_contact.display_name AS display_name,
name_raw_contact.display_name_alt AS display_name_alt,
name_raw_contact.phonetic_name AS phonetic_name,
name_raw_contact.phonetic_name_style AS phonetic_name_style,
name_raw_contact.sort_key AS sort_key,
name_raw_contact.sort_key_alt AS sort_key_alt,
has_phone_number,
has_valid_sip_account,
name_raw_contact_id,
lookup,
photo_id,
photo_file_id,
CAST(EXISTS (SELECT _id FROM visible_contacts WHERE contacts._id=visible_contacts._id) AS INTEGER) AS in_visible_group,
status_update_id,
contacts.last_time_contacted AS last_time_contacted,
contacts.send_to_voicemail AS send_to_voicemail,
contacts.starred AS starred,
contacts.times_contacted AS times_contacted,
(CASE WHEN photo_file_id IS NULL    
    THEN (
        CASE WHEN photo_id IS NULL OR photo_id=0
            THEN NULL
        ELSE 'content://com.android.contacts/contacts/'||contacts._id|| '/photo' END)
    ELSE 'content://com.android.contacts/display_photo/'||photo_file_id END) AS photo_uri,
(CASE WHEN photo_id IS NULL OR photo_id=0
    THEN NULL
    ELSE 'content://com.android.contacts/contacts/'||contacts._id|| '/photo' END) AS photo_thumb_uri,
0 AS is_user_profile,
name_raw_contact.view_mode AS view_mode,
name_raw_contact.sim_index AS sim_index

FROM contacts JOIN raw_contacts AS name_raw_contact ON(name_raw_contact_id=name_raw_contact._id)

视图:view_entities

合并raw_contacts和data,可以获得每个raw contacts的全部信息。

CREATE VIEW view_entities AS

SELECT raw_contacts.contact_id AS _id,
raw_contacts.contact_id AS contact_id,
raw_contacts.deleted AS deleted,
is_primary,
is_super_primary,
data_version,
data.package_id,
package AS res_package,
data.mimetype_id,
mimetype AS mimetype,
is_read_only,
data1, data2, data3, data4, data5, data6, data7, data8, data9, data10, data11, data12, data13, data14, data15,
data_sync1, data_sync2, data_sync3, data_sync4,
raw_contacts.account_id,
accounts.account_name AS account_name,
accounts.account_type AS account_type,
accounts.data_set AS data_set,

(CASE WHEN accounts.data_set IS NULL
    THEN accounts.account_type
    ELSE accounts.account_type||'/'||accounts.data_set END) AS account_type_and_data_set,

raw_contacts.sourceid AS sourceid,
raw_contacts.name_verified AS name_verified,
raw_contacts.version AS version,
raw_contacts.dirty AS dirty,
raw_contacts.sync1 AS sync1,raw_contacts.sync2 AS sync2,raw_contacts.sync3 AS sync3,raw_contacts.sync4 AS sync4,
contacts.custom_ringtone AS custom_ringtone,
name_raw_contact.display_name_source AS display_name_source,
name_raw_contact.display_name AS display_name,
name_raw_contact.display_name_alt AS display_name_alt,
name_raw_contact.phonetic_name AS phonetic_name,
name_raw_contact.phonetic_name_style AS phonetic_name_style,
name_raw_contact.sort_key AS sort_key,
name_raw_contact.phonebook_label AS phonebook_label,
name_raw_contact.phonebook_bucket AS phonebook_bucket,
name_raw_contact.sort_key_alt AS sort_key_alt,
name_raw_contact.phonebook_label_alt AS phonebook_label_alt,
name_raw_contact.phonebook_bucket_alt AS phonebook_bucket_alt,
has_phone_number,
name_raw_contact_id,
lookup,
photo_id,
photo_file_id,
CAST(EXISTS (SELECT _id FROM visible_contacts WHERE contacts._id=visible_contacts._id) AS INTEGER) AS in_visible_group,
status_update_id,
contacts.contact_last_updated_timestamp,
contacts.last_time_contacted AS last_time_contacted,
contacts.send_to_voicemail AS send_to_voicemail,
contacts.starred AS starred,
contacts.pinned AS pinned,
contacts.times_contacted AS times_contacted,
(CASE WHEN photo_file_id IS NULL
    THEN (CASE WHEN photo_id IS NULL OR photo_id=0
        THEN NULL
        ELSE 'content://com.android.contacts/contacts/'||raw_contacts.contact_id|| '/photo' END)
    ELSE 'content://com.android.contacts/display_photo/'||photo_file_id END) AS photo_uri,
(CASE WHEN photo_id IS NULL OR photo_id=0
    THEN NULL ELSE 'content://com.android.contacts/contacts/'||raw_contacts.contact_id|| '/photo' END)
    AS photo_thumb_uri,
0 AS is_user_profile,
data_sync1, data_sync2, data_sync3, data_sync4,
raw_contacts._id AS raw_contact_id,
data._id AS data_id,
groups.sourceid AS group_sourceid  FROM raw_contacts
    JOIN accounts ON (raw_contacts.account_id=accounts._id)
    JOIN contacts ON (raw_contacts.contact_id=contacts._id)
    JOIN raw_contacts AS name_raw_contact ON(name_raw_contact_id=name_raw_contact._id)
    LEFT OUTER JOIN data ON (data.raw_contact_id=raw_contacts._id)
    LEFT OUTER JOIN packages ON (data.package_id=packages._id)
    LEFT OUTER JOIN mimetypes ON (data.mimetype_id=mimetypes._id)
    LEFT OUTER JOIN groups ON (mimetypes.mimetype='vnd.android.cursor.item/group_membership' AND groups._id=data.data1)

相关链接:我的Android开发相关文章

你可能感兴趣的:(Pro Android学习笔记(一六十):联系人API(3):联系人数据)