文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处http://blog.csdn.net/flowingflying/以及作者@恺风Wei。
查看reference中android.provider.ContactsContract.CommonDataKinds可以知道该版本的Android API联系人中带有哪些信息。在API level 19中,我们看到有以下的信息:
而各个信息,例如Email,又有着他的结构,我们可以继续查看ContactsContract.CommondataKinds.Email。
一个账号account拥有其自己的联系人,这些联系人称为raw contacts,具有自己的数据信息,例如email,phone号码,地址等。Android在people应用中提供了raw contacts的整合,不同账号的raw contact进行整合,只在列表中出现一次。
联系人信息存放在/data/data/com.android.providers.contacts/databases中。
在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的定义:
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里面的定义。
在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 )
我们看一个查询的结果:
下面是表mimetype的内容,通过data中的mime_type_id可以检索具体的类型。用表格来存储类型,而不是进行固化,这可以灵活地增加、删除和修改定义,是个好的设计。
data表的各列也可以查看ContactsContract.Data,具体的某个mimetype对应的data1~data15各标识什么,可以查阅ContactsContract.CommonDataKinds.*,例如ContactsContract.CommonDataKinds.Phone。
在不同的账号下面可以会有相同的联系人,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(当属性变化是,并不整合到整合联系人中)。
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)
合并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开发相关文章