您的位置:首页 > 数据库

联系人Contacts中数据库contacts.db简要分析

2015-12-27 18:12 330 查看
在Contacts中,contacts2.db数据库位于/data/data/com.android.providers.contacts/databases里,contacts2.db中有很多张表,下面主要看下几张重要的表

创建contacts2.db的地方在packages/providers/ContactsProvider/src/com/android/providers/contacts/ContactsDatabaseHelper.java中,

里面定义了contact2.db数据里表名和视图名

public interface Tables {
public static final String CONTACTS = "contacts";
public static final String DELETED_CONTACTS = "deleted_contacts";
public static final String RAW_CONTACTS = "raw_contacts";
public static final String STREAM_ITEMS = "stream_items";
public static final String STREAM_ITEM_PHOTOS = "stream_item_photos";
public static final String PHOTO_FILES = "photo_files";
public static final String PACKAGES = "packages";
public static final String MIMETYPES = "mimetypes";
public static final String PHONE_LOOKUP = "phone_lookup";
public static final String NAME_LOOKUP = "name_lookup";
public static final String AGGREGATION_EXCEPTIONS = "agg_exceptions";
public static final String SETTINGS = "settings";
public static final String DATA = "data";
public static final String GROUPS = "groups";
public static final String PRESENCE = "presence";
public static final String AGGREGATED_PRESENCE = "agg_presence";
public static final String NICKNAME_LOOKUP = "nickname_lookup";
public static final String CALLS = "calls";
public static final String STATUS_UPDATES = "status_updates";
public static final String PROPERTIES = "properties";
public static final String ACCOUNTS = "accounts";
public static final String VISIBLE_CONTACTS = "visible_contacts";
public static final String DIRECTORIES = "directories";
public static final String DEFAULT_DIRECTORY = "default_directory";
public static final String SEARCH_INDEX = "search_index";
public static final String VOICEMAIL_STATUS = "voicemail_status";
public static final String PRE_AUTHORIZED_URIS = "pre_authorized_uris";
视图表的定义

public interface Views {
public static final String DATA = "view_data";
public static final String RAW_CONTACTS = "view_raw_contacts";
public static final String CONTACTS = "view_contacts";
public static final String ENTITIES = "view_entities";
public static final String RAW_ENTITIES = "view_raw_entities";
public static final String GROUPS = "view_groups";
public static final String DATA_USAGE_STAT = "view_data_usage_stat";
public static final String STREAM_ITEMS = "view_stream_items";
}


ContactsDatabaseHelper继承SQLiteOpenHelper在onCreate方法中创建了数据库

@Override
public void onCreate(SQLiteDatabase db) {
Log.i(TAG, "Bootstrapping database version: " + DATABASE_VERSION);

mSyncState.createDatabase(db);

// Create the properties table first so the create time is available as soon as possible.
// The create time is needed by BOOT_COMPLETE to send broadcasts.
db.execSQL("CREATE TABLE " + Tables.PROPERTIES + " (" +
PropertiesColumns.PROPERTY_KEY + " TEXT PRIMARY KEY, " +
PropertiesColumns.PROPERTY_VALUE + " TEXT " +
");");
setProperty(db, DbProperties.DATABASE_TIME_CREATED, String.valueOf(
System.currentTimeMillis()));

db.execSQL("CREATE TABLE " + Tables.ACCOUNTS + " (" +
AccountsColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
AccountsColumns.ACCOUNT_NAME + " TEXT, " +
AccountsColumns.ACCOUNT_TYPE + " TEXT, " +
AccountsColumns.DATA_SET + " TEXT" +
");");

// One row per group of contacts corresponding to the same person
db.execSQL("CREATE TABLE " + Tables.CONTACTS + " (" +
BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
Contacts.NAME_RAW_CONTACT_ID + " INTEGER REFERENCES raw_contacts(_id)," +
Contacts.PHOTO_ID + " INTEGER REFERENCES data(_id)," +
Contacts.PHOTO_FILE_ID + " INTEGER REFERENCES photo_files(_id)," +
Contacts.CUSTOM_RINGTONE + " TEXT," +
Contacts.SEND_TO_VOICEMAIL + " INTEGER NOT NULL DEFAULT 0," +
Contacts.TIMES_CONTACTED + " INTEGER NOT NULL DEFAULT 0," +
Contacts.LAST_TIME_CONTACTED + " INTEGER," +
Contacts.STARRED + " INTEGER NOT NULL DEFAULT 0," +
Contacts.PINNED + " INTEGER NOT NULL DEFAULT " + PinnedPositions.UNPINNED + "," +
Contacts.HAS_PHONE_NUMBER + " INTEGER NOT NULL DEFAULT 0," +
Contacts.LOOKUP_KEY + " TEXT," +
ContactsColumns.LAST_STATUS_UPDATE_ID + " INTEGER REFERENCES data(_id)," +
Contacts.CONTACT_LAST_UPDATED_TIMESTAMP + " INTEGER" +
");");

ContactsTableUtil.createIndexes(db);

// deleted_contacts table
DeletedContactsTableUtil.create(db);

// Raw_contacts table
db.execSQL("CREATE TABLE " + Tables.RAW_CONTACTS + " (" +
RawContacts._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
RawContactsColumns.ACCOUNT_ID + " INTEGER REFERENCES " +
Tables.ACCOUNTS + "(" + AccountsColumns._ID + ")," +
RawContacts.SOURCE_ID + " TEXT," +
RawContacts.BACKUP_ID + " TEXT," +
RawContacts.RAW_CONTACT_IS_READ_ONLY + " INTEGER NOT NULL DEFAULT 0," +
RawContacts.VERSION + " INTEGER NOT NULL DEFAULT 1," +
RawContacts.DIRTY + " INTEGER NOT NULL DEFAULT 0," +
RawContacts.DELETED + " INTEGER NOT NULL DEFAULT 0," +
RawContacts.CONTACT_ID + " INTEGER REFERENCES contacts(_id)," +
RawContacts.AGGREGATION_MODE + " INTEGER NOT NULL DEFAULT " +
RawContacts.AGGREGATION_MODE_DEFAULT + "," +
RawContactsColumns.AGGREGATION_NEEDED + " INTEGER NOT NULL DEFAULT 1," +
RawContacts.CUSTOM_RINGTONE + " TEXT," +
RawContacts.SEND_TO_VOICEMAIL + " INTEGER NOT NULL DEFAULT 0," +
RawContacts.TIMES_CONTACTED + " INTEGER NOT NULL DEFAULT 0," +
RawContacts.LAST_TIME_CONTACTED + " INTEGER," +
RawContacts.STARRED + " INTEGER NOT NULL DEFAULT 0," +
RawContacts.PINNED + " INTEGER NOT NULL DEFAULT "  + PinnedPositions.UNPINNED +
"," + RawContacts.DISPLAY_NAME_PRIMARY + " TEXT," +
RawContacts.DISPLAY_NAME_ALTERNATIVE + " TEXT," +
RawContacts.DISPLAY_NAME_SOURCE + " INTEGER NOT NULL DEFAULT " +
DisplayNameSources.UNDEFINED + "," +
RawContacts.PHONETIC_NAME + " TEXT," +
// TODO: PHONETIC_NAME_STYLE should be INTEGER. There is a
// mismatch between how the column is created here (TEXT) and
// how it is created in upgradeToVersion205 (INTEGER).
RawContacts.PHONETIC_NAME_STYLE + " TEXT," +
RawContacts.SORT_KEY_PRIMARY + " TEXT COLLATE " +
ContactsProvider2.PHONEBOOK_COLLATOR_NAME + "," +
RawContactsColumns.PHONEBOOK_LABEL_PRIMARY + " TEXT," +
RawContactsColumns.PHONEBOOK_BUCKET_PRIMARY + " INTEGER," +
RawContacts.SORT_KEY_ALTERNATIVE + " TEXT COLLATE " +
ContactsProvider2.PHONEBOOK_COLLATOR_NAME + "," +
RawContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE + " TEXT," +
RawContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE + " INTEGER," +
RawContactsColumns.NAME_VERIFIED_OBSOLETE + " INTEGER NOT NULL DEFAULT 0," +
RawContacts.SYNC1 + " TEXT, " +
RawContacts.SYNC2 + " TEXT, " +
RawContacts.SYNC3 + " TEXT, " +
RawContacts.SYNC4 + " TEXT " +
");");

db.execSQL("CREATE INDEX raw_contacts_contact_id_index ON " + Tables.RAW_CONTACTS + " (" +
RawContacts.CONTACT_ID +
");");

db.execSQL("CREATE INDEX raw_contacts_source_id_account_id_index ON " +
Tables.RAW_CONTACTS + " (" +
RawContacts.SOURCE_ID + ", " +
RawContactsColumns.ACCOUNT_ID +
");");

db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS raw_contacts_backup_id_account_id_index ON " +
Tables.RAW_CONTACTS + " (" +
RawContacts.BACKUP_ID + ", " +
RawContactsColumns.ACCOUNT_ID +
");");

db.execSQL("CREATE TABLE " + Tables.STREAM_ITEMS + " (" +
StreamItems._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
StreamItems.RAW_CONTACT_ID + " INTEGER NOT NULL, " +
StreamItems.RES_PACKAGE + " TEXT, " +
StreamItems.RES_ICON + " TEXT, " +
StreamItems.RES_LABEL + " TEXT, " +
StreamItems.TEXT + " TEXT, " +
StreamItems.TIMESTAMP + " INTEGER NOT NULL, " +
StreamItems.COMMENTS + " TEXT, " +
StreamItems.SYNC1 + " TEXT, " +
StreamItems.SYNC2 + " TEXT, " +
StreamItems.SYNC3 + " TEXT, " +
StreamItems.SYNC4 + " TEXT, " +
"FOREIGN KEY(" + StreamItems.RAW_CONTACT_ID + ") REFERENCES " +
Tables.RAW_CONTACTS + "(" + RawContacts._ID + "));");

db.execSQL("CREATE TABLE " + Tables.STREAM_ITEM_PHOTOS + " (" +
StreamItemPhotos._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
StreamItemPhotos.STREAM_ITEM_ID + " INTEGER NOT NULL, " +
StreamItemPhotos.SORT_INDEX + " INTEGER, " +
StreamItemPhotos.PHOTO_FILE_ID + " INTEGER NOT NULL, " +
StreamItemPhotos.SYNC1 + " TEXT, " +
StreamItemPhotos.SYNC2 + " TEXT, " +
StreamItemPhotos.SYNC3 + " TEXT, " +
StreamItemPhotos.SYNC4 + " TEXT, " +
"FOREIGN KEY(" + StreamItemPhotos.STREAM_ITEM_ID + ") REFERENCES " +
Tables.STREAM_ITEMS + "(" + StreamItems._ID + "));");

db.execSQL("CREATE TABLE " + Tables.PHOTO_FILES + " (" +
PhotoFiles._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
PhotoFiles.HEIGHT + " INTEGER NOT NULL, " +
PhotoFiles.WIDTH + " INTEGER NOT NULL, " +
PhotoFiles.FILESIZE + " INTEGER NOT NULL);");

// TODO readd the index and investigate a controlled use of it
//        db.execSQL("CREATE INDEX raw_contacts_agg_index ON " + Tables.RAW_CONTACTS + " (" +
//                RawContactsColumns.AGGREGATION_NEEDED +
//        ");");

// Package name mapping table
db.execSQL("CREATE TABLE " + Tables.PACKAGES + " (" +
PackagesColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
PackagesColumns.PACKAGE + " TEXT NOT NULL" +
");");

// Mimetype mapping table
db.execSQL("CREATE TABLE " + Tables.MIMETYPES + " (" +
MimetypesColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
MimetypesColumns.MIMETYPE + " TEXT NOT NULL" +
");");

// Mimetype table requires an index on mime type
db.execSQL("CREATE UNIQUE INDEX mime_type ON " + Tables.MIMETYPES + " (" +
MimetypesColumns.MIMETYPE +
");");

// Public generic data table
db.execSQL("CREATE TABLE " + Tables.DATA + " (" +
Data._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
DataColumns.PACKAGE_ID + " INTEGER REFERENCES package(_id)," +
DataColumns.MIMETYPE_ID + " INTEGER REFERENCES mimetype(_id) NOT NULL," +
Data.RAW_CONTACT_ID + " INTEGER REFERENCES raw_contacts(_id) NOT NULL," +
Data.HASH_ID + " TEXT," +
Data.IS_READ_ONLY + " INTEGER NOT NULL DEFAULT 0," +
Data.IS_PRIMARY + " INTEGER NOT NULL DEFAULT 0," +
Data.IS_SUPER_PRIMARY + " INTEGER NOT NULL DEFAULT 0," +
Data.DATA_VERSION + " INTEGER NOT NULL DEFAULT 0," +
Data.DATA1 + " TEXT," +
Data.DATA2 + " TEXT," +
Data.DATA3 + " TEXT," +
Data.DATA4 + " TEXT," +
Data.DATA5 + " TEXT," +
Data.DATA6 + " TEXT," +
Data.DATA7 + " TEXT," +
Data.DATA8 + " TEXT," +
Data.DATA9 + " TEXT," +
Data.DATA10 + " TEXT," +
Data.DATA11 + " TEXT," +
Data.DATA12 + " TEXT," +
Data.DATA13 + " TEXT," +
Data.DATA14 + " TEXT," +
Data.DATA15 + " TEXT," +
Data.SYNC1 + " TEXT, " +
Data.SYNC2 + " TEXT, " +
Data.SYNC3 + " TEXT, " +
Data.SYNC4 + " TEXT, " +
Data.CARRIER_PRESENCE + " INTEGER NOT NULL DEFAULT 0 " +
");");

db.execSQL("CREATE INDEX data_raw_contact_id ON " + Tables.DATA + " (" +
Data.RAW_CONTACT_ID +
");");

/**
* For email lookup and similar queries.
*/
db.execSQL("CREATE INDEX data_mimetype_data1_index ON " + Tables.DATA + " (" +
DataColumns.MIMETYPE_ID + "," +
Data.DATA1 +
");");

/**
* For contact backup restore queries.
*/
db.execSQL("CREATE INDEX IF NOT EXISTS data_hash_id_index ON " + Tables.DATA + " (" +
Data.HASH_ID +
");");

// Private phone numbers table used for lookup
db.execSQL("CREATE TABLE " + Tables.PHONE_LOOKUP + " (" +
PhoneLookupColumns.DATA_ID
+ " INTEGER REFERENCES data(_id) NOT NULL," +
PhoneLookupColumns.RAW_CONTACT_ID
+ " INTEGER REFERENCES raw_contacts(_id) NOT NULL," +
PhoneLookupColumns.NORMALIZED_NUMBER + " TEXT NOT NULL," +
PhoneLookupColumns.MIN_MATCH + " TEXT NOT NULL" +
");");

db.execSQL("CREATE INDEX phone_lookup_index ON " + Tables.PHONE_LOOKUP + " (" +
PhoneLookupColumns.NORMALIZED_NUMBER + "," +
PhoneLookupColumns.RAW_CONTACT_ID + "," +
PhoneLookupColumns.DATA_ID +
");");

db.execSQL("CREATE INDEX phone_lookup_min_match_index ON " + Tables.PHONE_LOOKUP + " (" +
PhoneLookupColumns.MIN_MATCH + "," +
PhoneLookupColumns.RAW_CONTACT_ID + "," +
PhoneLookupColumns.DATA_ID +
");");

db.execSQL("CREATE INDEX phone_lookup_data_id_min_match_index ON " + Tables.PHONE_LOOKUP +
" (" + PhoneLookupColumns.DATA_ID + ", " + PhoneLookupColumns.MIN_MATCH + ");");

// Private name/nickname table used for lookup.
db.execSQL("CREATE TABLE " + Tables.NAME_LOOKUP + " (" +
NameLookupColumns.DATA_ID
+ " INTEGER REFERENCES data(_id) NOT NULL," +
NameLookupColumns.RAW_CONTACT_ID
+ " INTEGER REFERENCES raw_contacts(_id) NOT NULL," +
NameLookupColumns.NORMALIZED_NAME + " TEXT NOT NULL," +
NameLookupColumns.NAME_TYPE + " INTEGER NOT NULL," +
"PRIMARY KEY ("
+ NameLookupColumns.DATA_ID + ", "
+ NameLookupColumns.NORMALIZED_NAME + ", "
+ NameLookupColumns.NAME_TYPE + ")" +
");");

db.execSQL("CREATE INDEX name_lookup_raw_contact_id_index ON " + Tables.NAME_LOOKUP + " (" +
NameLookupColumns.RAW_CONTACT_ID +
");");

db.execSQL("CREATE TABLE " + Tables.NICKNAME_LOOKUP + " (" +
NicknameLookupColumns.NAME + " TEXT," +
NicknameLookupColumns.CLUSTER + " TEXT" +
");");

db.execSQL("CREATE UNIQUE INDEX nickname_lookup_index ON " + Tables.NICKNAME_LOOKUP + " (" +
NicknameLookupColumns.NAME + ", " +
NicknameLookupColumns.CLUSTER +
");");

// Groups table.
db.execSQL("CREATE TABLE " + Tables.GROUPS + " (" +
Groups._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
GroupsColumns.PACKAGE_ID + " INTEGER REFERENCES package(_id)," +
GroupsColumns.ACCOUNT_ID + " INTEGER REFERENCES " +
Tables.ACCOUNTS + "(" + AccountsColumns._ID + ")," +
Groups.SOURCE_ID + " TEXT," +
Groups.VERSION + " INTEGER NOT NULL DEFAULT 1," +
Groups.DIRTY + " INTEGER NOT NULL DEFAULT 0," +
Groups.TITLE + " TEXT," +
Groups.TITLE_RES + " INTEGER," +
Groups.NOTES + " TEXT," +
Groups.SYSTEM_ID + " TEXT," +
Groups.DELETED + " INTEGER NOT NULL DEFAULT 0," +
Groups.GROUP_VISIBLE + " INTEGER NOT NULL DEFAULT 0," +
Groups.SHOULD_SYNC + " INTEGER NOT NULL DEFAULT 1," +
Groups.AUTO_ADD + " INTEGER NOT NULL DEFAULT 0," +
Groups.FAVORITES + " INTEGER NOT NULL DEFAULT 0," +
Groups.GROUP_IS_READ_ONLY + " INTEGER NOT NULL DEFAULT 0," +
Groups.SYNC1 + " TEXT, " +
Groups.SYNC2 + " TEXT, " +
Groups.SYNC3 + " TEXT, " +
Groups.SYNC4 + " TEXT " +
");");

db.execSQL("CREATE INDEX groups_source_id_account_id_index ON " + Tables.GROUPS + " (" +
Groups.SOURCE_ID + ", " +
GroupsColumns.ACCOUNT_ID +
");");

db.execSQL("CREATE TABLE IF NOT EXISTS " + Tables.AGGREGATION_EXCEPTIONS + " (" +
AggregationExceptionColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
AggregationExceptions.TYPE + " INTEGER NOT NULL, " +
AggregationExceptions.RAW_CONTACT_ID1
+ " INTEGER REFERENCES raw_contacts(_id), " +
AggregationExceptions.RAW_CONTACT_ID2
+ " INTEGER REFERENCES raw_contacts(_id)" +
");");

db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS aggregation_exception_index1 ON " +
Tables.AGGREGATION_EXCEPTIONS + " (" +
AggregationExceptions.RAW_CONTACT_ID1 + ", " +
AggregationExceptions.RAW_CONTACT_ID2 +
");");

db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS aggregation_exception_index2 ON " +
Tables.AGGREGATION_EXCEPTIONS + " (" +
AggregationExceptions.RAW_CONTACT_ID2 + ", " +
AggregationExceptions.RAW_CONTACT_ID1 +
");");

db.execSQL("CREATE TABLE IF NOT EXISTS " + Tables.SETTINGS + " (" +
Settings.ACCOUNT_NAME + " STRING NOT NULL," +
Settings.ACCOUNT_TYPE + " STRING NOT NULL," +
Settings.DATA_SET + " STRING," +
Settings.UNGROUPED_VISIBLE + " INTEGER NOT NULL DEFAULT 0," +
Settings.SHOULD_SYNC + " INTEGER NOT NULL DEFAULT 1" +
");");

db.execSQL("CREATE TABLE " + Tables.VISIBLE_CONTACTS + " (" +
Contacts._ID + " INTEGER PRIMARY KEY" +
");");

db.execSQL("CREATE TABLE " + Tables.DEFAULT_DIRECTORY + " (" +
Contacts._ID + " INTEGER PRIMARY KEY" +
");");

// The table for recent calls is here so we can do table joins on people, phones, and
// calls all in one place.
// NOTE: When adding a new column to Tables.CALLS, make sure to also add it to
// CallLogProvider.CALL_LOG_SYNC_PROJECTION, if it is a column that should be copied to
// the call log of secondary users.
db.execSQL("CREATE TABLE " + Tables.CALLS + " (" +
Calls._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
Calls.NUMBER + " TEXT," +
Calls.NUMBER_PRESENTATION + " INTEGER NOT NULL DEFAULT " +
Calls.PRESENTATION_ALLOWED + "," +
Calls.DATE + " INTEGER," +
Calls.DURATION + " INTEGER," +
Calls.DATA_USAGE + " INTEGER," +
Calls.TYPE + " INTEGER," +
Calls.FEATURES + " INTEGER NOT NULL DEFAULT 0," +
Calls.PHONE_ACCOUNT_COMPONENT_NAME + " TEXT," +
Calls.PHONE_ACCOUNT_ID + " TEXT," +
Calls.PHONE_ACCOUNT_ADDRESS + " TEXT," +
Calls.PHONE_ACCOUNT_HIDDEN + " INTEGER NOT NULL DEFAULT 0," +
Calls.SUB_ID + " INTEGER DEFAULT -1," +
Calls.NEW + " INTEGER," +
Calls.CACHED_NAME + " TEXT," +
Calls.CACHED_NUMBER_TYPE + " INTEGER," +
Calls.CACHED_NUMBER_LABEL + " TEXT," +
Calls.COUNTRY_ISO + " TEXT," +
Calls.VOICEMAIL_URI + " TEXT," +
Calls.IS_READ + " INTEGER," +
Calls.GEOCODED_LOCATION + " TEXT," +
Calls.CACHED_LOOKUP_URI + " TEXT," +
Calls.CACHED_MATCHED_NUMBER + " TEXT," +
Calls.CACHED_NORMALIZED_NUMBER + " TEXT," +
Calls.CACHED_PHOTO_ID + " INTEGER NOT NULL DEFAULT 0," +
Calls.CACHED_PHOTO_URI + " TEXT," +
Calls.CACHED_FORMATTED_NUMBER + " TEXT," +
Voicemails._DATA + " TEXT," +
Voicemails.HAS_CONTENT + " INTEGER," +
Voicemails.MIME_TYPE + " TEXT," +
Voicemails.SOURCE_DATA + " TEXT," +
Voicemails.SOURCE_PACKAGE + " TEXT," +
Voicemails.TRANSCRIPTION + " TEXT," +
Voicemails.STATE + " INTEGER," +
Voicemails.DIRTY + " INTEGER NOT NULL DEFAULT 0," +
Voicemails.DELETED + " INTEGER NOT NULL DEFAULT 0" +
");");

// Voicemail source status table.
db.execSQL("CREATE TABLE " + Tables.VOICEMAIL_STATUS + " (" +
VoicemailContract.Status._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
VoicemailContract.Status.SOURCE_PACKAGE + " TEXT UNIQUE NOT NULL," +
VoicemailContract.Status.PHONE_ACCOUNT_COMPONENT_NAME + " TEXT," +
VoicemailContract.Status.PHONE_ACCOUNT_ID + " TEXT," +
VoicemailContract.Status.SETTINGS_URI + " TEXT," +
VoicemailContract.Status.VOICEMAIL_ACCESS_URI + " TEXT," +
VoicemailContract.Status.CONFIGURATION_STATE + " INTEGER," +
VoicemailContract.Status.DATA_CHANNEL_STATE + " INTEGER," +
VoicemailContract.Status.NOTIFICATION_CHANNEL_STATE + " INTEGER" +
");");

db.execSQL("CREATE TABLE " + Tables.STATUS_UPDATES + " (" +
StatusUpdatesColumns.DATA_ID + " INTEGER PRIMARY KEY REFERENCES data(_id)," +
StatusUpdates.STATUS + " TEXT," +
StatusUpdates.STATUS_TIMESTAMP + " INTEGER," +
StatusUpdates.STATUS_RES_PACKAGE + " TEXT, " +
StatusUpdates.STATUS_LABEL + " INTEGER, " +
StatusUpdates.STATUS_ICON + " INTEGER" +
");");

createDirectoriesTable(db);
createSearchIndexTable(db, false /* we build stats table later */);

db.execSQL("CREATE TABLE " + Tables.DATA_USAGE_STAT + "(" +
DataUsageStatColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
DataUsageStatColumns.DATA_ID + " INTEGER NOT NULL, " +
DataUsageStatColumns.USAGE_TYPE_INT + " INTEGER NOT NULL DEFAULT 0, " +
DataUsageStatColumns.TIMES_USED + " INTEGER NOT NULL DEFAULT 0, " +
DataUsageStatColumns.LAST_TIME_USED + " INTERGER NOT NULL DEFAULT 0, " +
"FOREIGN KEY(" + DataUsageStatColumns.DATA_ID + ") REFERENCES "
+ Tables.DATA + "(" + Data._ID + ")" +
");");
db.execSQL("CREATE UNIQUE INDEX data_usage_stat_index ON " +
Tables.DATA_USAGE_STAT + " (" +
DataUsageStatColumns.DATA_ID + ", " +
DataUsageStatColumns.USAGE_TYPE_INT +
");");

db.execSQL("CREATE TABLE " + Tables.PRE_AUTHORIZED_URIS + " ("+
PreAuthorizedUris._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
PreAuthorizedUris.URI + " STRING NOT NULL, " +
PreAuthorizedUris.EXPIRATION + " INTEGER NOT NULL DEFAULT 0);");

// When adding new tables, be sure to also add size-estimates in updateSqliteStats
createContactsViews(db);
createGroupsView(db);
createContactsTriggers(db);
createContactsIndexes(db, false /* we build stats table later */);

loadNicknameLookupTable(db);

// Set sequence starts.
initializeAutoIncrementSequences(db);

// Add the legacy API support views, etc.
LegacyApiSupport.createDatabase(db);

if (mDatabaseOptimizationEnabled) {
// This will create a sqlite_stat1 table that is used for query optimization
db.execSQL("ANALYZE;");

updateSqliteStats(db);
}

ContentResolver.requestSync(null /* all accounts */,
ContactsContract.AUTHORITY, new Bundle());

// Only send broadcasts for regular contacts db.
if (dbForProfile() == 0) {
final Intent dbCreatedIntent = new Intent(
ContactsContract.Intents.CONTACTS_DATABASE_CREATED);
dbCreatedIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcast(dbCreatedIntent, android.Manifest.permission.READ_CONTACTS);
}
}


这里以创建contacts表为例简要介绍下

db.execSQL("CREATE TABLE " + Tables.CONTACTS + " (" +
BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
Contacts.NAME_RAW_CONTACT_ID + " INTEGER REFERENCES raw_contacts(_id)," +
Contacts.PHOTO_ID + " INTEGER REFERENCES data(_id)," +
Contacts.PHOTO_FILE_ID + " INTEGER REFERENCES photo_files(_id)," +
Contacts.CUSTOM_RINGTONE + " TEXT," +
Contacts.SEND_TO_VOICEMAIL + " INTEGER NOT NULL DEFAULT 0," +
Contacts.TIMES_CONTACTED + " INTEGER NOT NULL DEFAULT 0," +
Contacts.LAST_TIME_CONTACTED + " INTEGER," +
Contacts.STARRED + " INTEGER NOT NULL DEFAULT 0," +
Contacts.PINNED + " INTEGER NOT NULL DEFAULT " + PinnedPositions.UNPINNED + "," +
Contacts.HAS_PHONE_NUMBER + " INTEGER NOT NULL DEFAULT 0," +
Contacts.LOOKUP_KEY + " TEXT," +
ContactsColumns.LAST_STATUS_UPDATE_ID + " INTEGER REFERENCES data(_id)," +
Contacts.CONTACT_LAST_UPDATED_TIMESTAMP + " INTEGER" +
");");


创建表的语句和sql语句差不多,创建表的主键,自动增加
BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
外键约束,contacts表中字段NAME_RAW_CONTACT_ID为raw_contacts表的主键,另外外键约束的类似

Contacts.NAME_RAW_CONTACT_ID + " INTEGER REFERENCES raw_contacts(_id)," +
Contacts.PHOTO_ID + " INTEGER REFERENCES data(_id)," +
Contacts.PHOTO_FILE_ID + " INTEGER REFERENCES photo_files(_id)," +


在这个类中除了创建了数据库表,还为有些表创建了触发器,视图,索引,下面每个都以一个简单的例子说下,有兴趣的话可以自己去查看源码

为data表创建触发器,如果raw_contact表中某条数据被删除,自动删除data表中对应的数据

db.execSQL("DROP TRIGGER IF EXISTS " + Tables.RAW_CONTACTS + "_deleted;");
db.execSQL("CREATE TRIGGER " + Tables.RAW_CONTACTS + "_deleted "
+ "   BEFORE DELETE ON " + Tables.RAW_CONTACTS
+ " BEGIN "
+ "   DELETE FROM " + Tables.DATA
+ "     WHERE " + Data.RAW_CONTACT_ID
+ "=OLD." + RawContacts._ID + ";"
+ "   DELETE FROM " + Tables.AGGREGATION_EXCEPTIONS
+ "     WHERE " + AggregationExceptions.RAW_CONTACT_ID1
+ "=OLD." + RawContacts._ID
+ "        OR " + AggregationExceptions.RAW_CONTACT_ID2
+ "=OLD." + RawContacts._ID + ";"
+ "   DELETE FROM " + Tables.VISIBLE_CONTACTS
+ "     WHERE " + Contacts._ID + "=OLD." + RawContacts.CONTACT_ID
+ "       AND (SELECT COUNT(*) FROM " + Tables.RAW_CONTACTS
+ "            WHERE " + RawContacts.CONTACT_ID + "=OLD." + RawContacts.CONTACT_ID
+ "           )=1;"
+ "   DELETE FROM " + Tables.DEFAULT_DIRECTORY
+ "     WHERE " + Contacts._ID + "=OLD." + RawContacts.CONTACT_ID
+ "       AND (SELECT COUNT(*) FROM " + Tables.RAW_CONTACTS
+ "            WHERE " + RawContacts.CONTACT_ID + "=OLD." + RawContacts.CONTACT_ID
+ "           )=1;"
+ "   DELETE FROM " + Tables.CONTACTS
+ "     WHERE " + Contacts._ID + "=OLD." + RawContacts.CONTACT_ID
+ "       AND (SELECT COUNT(*) FROM " + Tables.RAW_CONTACTS
+ "            WHERE " + RawContacts.CONTACT_ID + "=OLD." + RawContacts.CONTACT_ID
+ "           )=1;"
+ " END");


为raw_contacts创建视图表,视图总是显示最近的数据。每当用户查询视图时,数据库引擎通过使用 SQL 语句来重建数据。

String rawContactsSelect = "SELECT "
+ RawContactsColumns.CONCRETE_ID + " AS " + RawContacts._ID + ","
+ RawContacts.CONTACT_ID + ", "
+ RawContacts.AGGREGATION_MODE + ", "
+ RawContacts.RAW_CONTACT_IS_READ_ONLY + ", "
+ RawContacts.DELETED + ", "
+ RawContacts.DISPLAY_NAME_SOURCE  + ", "
+ RawContacts.DISPLAY_NAME_PRIMARY  + ", "
+ RawContacts.DISPLAY_NAME_ALTERNATIVE  + ", "
+ RawContacts.PHONETIC_NAME  + ", "
+ RawContacts.PHONETIC_NAME_STYLE  + ", "
+ RawContacts.SORT_KEY_PRIMARY  + ", "
+ RawContactsColumns.PHONEBOOK_LABEL_PRIMARY  + ", "
+ RawContactsColumns.PHONEBOOK_BUCKET_PRIMARY  + ", "
+ RawContacts.SORT_KEY_ALTERNATIVE + ", "
+ RawContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE  + ", "
+ RawContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE  + ", "
+ dbForProfile() + " AS " + RawContacts.RAW_CONTACT_IS_USER_PROFILE + ", "
+ rawContactOptionColumns + ", "
+ syncColumns
+ " FROM " + Tables.RAW_CONTACTS
+ " JOIN " + Tables.ACCOUNTS + " ON ("
+   RawContactsColumns.CONCRETE_ACCOUNT_ID + "=" + AccountsColumns.CONCRETE_ID
+ ")";

db.execSQL("CREATE VIEW " + Views.RAW_CONTACTS + " AS " + rawContactsSelect);


表中创建索引,以便更加快速高效地查询数据,用户无法看到索引,它们只能被用来加速搜索/查询,更新一个包含索引的表需要比更新一个没有索引的表更多的时间,这是由于索引本身也需要更新。因此,理想的做法是仅仅在常常被搜索的列(以及表)上面创建索引。

在NAME_LOOKUP表中的raw_contact_id列上创建名为name_lookup_raw_contact_id_index的索引

db.execSQL("CREATE INDEX name_lookup_raw_contact_id_index ON " + Tables.NAME_LOOKUP + " (" +
NameLookupColumns.RAW_CONTACT_ID +
");");


在联系人中使用数据库的时候,一般都是通过ContentProvider来操作contact2.db里的数据,在ContactsProvider2中定义了操作不同表的uri,在contentProvider中根据不同的uri来操作不同的表

static {
// Contacts URI matching table
final UriMatcher matcher = sUriMatcher;

// DO NOT use constants such as Contacts.CONTENT_URI here.  This is the only place
// where one can see all supported URLs at a glance, and using constants will reduce
// readability.
matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_ID_DATA);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/entities", CONTACTS_ID_ENTITIES);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions",
AGGREGATION_SUGGESTIONS);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions/*",
AGGREGATION_SUGGESTIONS);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_ID_PHOTO);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/display_photo",
CONTACTS_ID_DISPLAY_PHOTO);

// Special URIs that refer to contact pictures in the corp CP2.
matcher.addURI(ContactsContract.AUTHORITY, "contacts_corp/#/photo", CONTACTS_ID_PHOTO_CORP);
matcher.addURI(ContactsContract.AUTHORITY, "contacts_corp/#/display_photo",
CONTACTS_ID_DISPLAY_PHOTO_CORP);

matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/stream_items",
CONTACTS_ID_STREAM_ITEMS);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter", CONTACTS_FILTER);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/data", CONTACTS_LOOKUP_DATA);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/photo",
CONTACTS_LOOKUP_PHOTO);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/data",
CONTACTS_LOOKUP_ID_DATA);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/photo",
CONTACTS_LOOKUP_ID_PHOTO);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/display_photo",
CONTACTS_LOOKUP_DISPLAY_PHOTO);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/display_photo",
CONTACTS_LOOKUP_ID_DISPLAY_PHOTO);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/entities",
CONTACTS_LOOKUP_ENTITIES);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/entities",
CONTACTS_LOOKUP_ID_ENTITIES);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/stream_items",
CONTACTS_LOOKUP_STREAM_ITEMS);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/stream_items",
CONTACTS_LOOKUP_ID_STREAM_ITEMS);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_vcard/*", CONTACTS_AS_VCARD);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_multi_vcard/*",
CONTACTS_AS_MULTI_VCARD);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*",
CONTACTS_STREQUENT_FILTER);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/frequent", CONTACTS_FREQUENT);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/delete_usage", CONTACTS_DELETE_USAGE);

matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS);
matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID);
matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_ID_DATA);
matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/display_photo",
RAW_CONTACTS_ID_DISPLAY_PHOTO);
matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/entity", RAW_CONTACT_ID_ENTITY);
matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/stream_items",
RAW_CONTACTS_ID_STREAM_ITEMS);
matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/stream_items/#",
RAW_CONTACTS_ID_STREAM_ITEMS_ID);

matcher.addURI(ContactsContract.AUTHORITY, "raw_contact_entities", RAW_CONTACT_ENTITIES);
matcher.addURI(ContactsContract.AUTHORITY, "raw_contact_entities_corp", RAW_CONTACT_ENTITIES_CORP);

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_enterprise/phones", PHONES_ENTERPRISE);
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/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/emails/lookup_enterprise",
EMAILS_LOOKUP_ENTERPRISE);
matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup_enterprise/*",
EMAILS_LOOKUP_ENTERPRISE);
matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS);
matcher.addURI(ContactsContract.AUTHORITY, "data/postals/#", POSTALS_ID);
/** "*" is in CSV form with data IDs ("123,456,789") */
matcher.addURI(ContactsContract.AUTHORITY, "data/usagefeedback/*", DATA_USAGE_FEEDBACK_ID);
matcher.addURI(ContactsContract.AUTHORITY, "data/callables/", CALLABLES);
matcher.addURI(ContactsContract.AUTHORITY, "data/callables/#", CALLABLES_ID);
matcher.addURI(ContactsContract.AUTHORITY, "data/callables/filter", CALLABLES_FILTER);
matcher.addURI(ContactsContract.AUTHORITY, "data/callables/filter/*", CALLABLES_FILTER);

matcher.addURI(ContactsContract.AUTHORITY, "data/contactables/", CONTACTABLES);
matcher.addURI(ContactsContract.AUTHORITY, "data/contactables/filter", CONTACTABLES_FILTER);
matcher.addURI(ContactsContract.AUTHORITY, "data/contactables/filter/*",
CONTACTABLES_FILTER);

matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS);
matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID);
matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY);

matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE);
matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH + "/#",
SYNCSTATE_ID);
matcher.addURI(ContactsContract.AUTHORITY, "profile/" + SyncStateContentProviderHelper.PATH,
PROFILE_SYNCSTATE);
matcher.addURI(ContactsContract.AUTHORITY,
"profile/" + SyncStateContentProviderHelper.PATH + "/#",
PROFILE_SYNCSTATE_ID);

matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP);
matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup_enterprise/*",
PHONE_LOOKUP_ENTERPRISE);
matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions",
AGGREGATION_EXCEPTIONS);
matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*",
AGGREGATION_EXCEPTION_ID);

matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS);

matcher.addURI(ContactsContract.AUTHORITY, "status_updates", STATUS_UPDATES);
matcher.addURI(ContactsContract.AUTHORITY, "status_updates/#", STATUS_UPDATES_ID);

matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,
SEARCH_SUGGESTIONS);
matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*",
SEARCH_SUGGESTIONS);
matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*",
SEARCH_SHORTCUT);

matcher.addURI(ContactsContract.AUTHORITY, "provider_status", PROVIDER_STATUS);

matcher.addURI(ContactsContract.AUTHORITY, "directories", DIRECTORIES);
matcher.addURI(ContactsContract.AUTHORITY, "directories/#", DIRECTORIES_ID);

matcher.addURI(ContactsContract.AUTHORITY, "complete_name", COMPLETE_NAME);

matcher.addURI(ContactsContract.AUTHORITY, "profile", PROFILE);
matcher.addURI(ContactsContract.AUTHORITY, "profile/entities", PROFILE_ENTITIES);
matcher.addURI(ContactsContract.AUTHORITY, "profile/data", PROFILE_DATA);
matcher.addURI(ContactsContract.AUTHORITY, "profile/data/#", PROFILE_DATA_ID);
matcher.addURI(ContactsContract.AUTHORITY, "profile/photo", PROFILE_PHOTO);
matcher.addURI(ContactsContract.AUTHORITY, "profile/display_photo", PROFILE_DISPLAY_PHOTO);
matcher.addURI(ContactsContract.AUTHORITY, "profile/as_vcard", PROFILE_AS_VCARD);
matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts", PROFILE_RAW_CONTACTS);
matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#",
PROFILE_RAW_CONTACTS_ID);
matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/data",
PROFILE_RAW_CONTACTS_ID_DATA);
matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/entity",
PROFILE_RAW_CONTACTS_ID_ENTITIES);
matcher.addURI(ContactsContract.AUTHORITY, "profile/status_updates",
PROFILE_STATUS_UPDATES);
matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contact_entities",
PROFILE_RAW_CONTACT_ENTITIES);

matcher.addURI(ContactsContract.AUTHORITY, "stream_items", STREAM_ITEMS);
matcher.addURI(ContactsContract.AUTHORITY, "stream_items/photo", STREAM_ITEMS_PHOTOS);
matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#", STREAM_ITEMS_ID);
matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo", STREAM_ITEMS_ID_PHOTOS);
matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo/#",
STREAM_ITEMS_ID_PHOTOS_ID);
matcher.addURI(ContactsContract.AUTHORITY, "stream_items_limit", STREAM_ITEMS_LIMIT);

matcher.addURI(ContactsContract.AUTHORITY, "display_photo/#", DISPLAY_PHOTO_ID);
matcher.addURI(ContactsContract.AUTHORITY, "photo_dimensions", PHOTO_DIMENSIONS);

matcher.addURI(ContactsContract.AUTHORITY, "deleted_contacts", DELETED_CONTACTS);
matcher.addURI(ContactsContract.AUTHORITY, "deleted_contacts/#", DELETED_CONTACTS_ID);
}


在Contacts中,有时候看到查询的uri明明是对应raw_contacts表,但真在在查询数据库的时候却是查询view_raw_contacts里的数据

Cursor cursor = mContentResolver.query(
RawContacts.CONTENT_URI, PROJECTION_FILTERED_MEMBERS,
accountClause + " AND (" +
RawContacts.DISPLAY_NAME_PRIMARY + " LIKE ? OR " +
RawContacts.DISPLAY_NAME_ALTERNATIVE + " LIKE ? )",
args, RawContacts.DISPLAY_NAME_PRIMARY + " COLLATE LOCALIZED ASC");


RawContacts.CONTENT_URI定义如下:

/**
* The content:// style URI for this table, which requests a directory of
* raw contact rows matching the selection criteria.
*/
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "raw_contacts");


下面来看看为啥在查询上面的uri时,会查询到view_raw_contacts里,ContentProvider在提供数据共享时,需要重写增删改查这四个方法,主要说下query这个方法的重写

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
return query(uri, projection, selection, selectionArgs, sortOrder, null);
}

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder, CancellationSignal cancellationSignal) {
if (VERBOSE_LOGGING) {
Log.v(TAG, "query: uri=" + uri + "  projection=" + Arrays.toString(projection) +
"  selection=[" + selection + "]  args=" + Arrays.toString(selectionArgs) +
"  order=[" + sortOrder + "] CPID=" + Binder.getCallingPid() +
" User=" + UserUtils.getCurrentUserHandle(getContext()));
}

waitForAccess(mReadAccessLatch);

// Query the profile DB if appropriate.
if (mapsToProfileDb(uri)) {
switchToProfileMode();
return mProfileProvider.query(uri, projection, selection, selectionArgs, sortOrder,
cancellationSignal);
}

// Otherwise proceed with a normal query against the contacts DB.
switchToContactMode();

String directory = getQueryParameter(uri, ContactsContract.DIRECTORY_PARAM_KEY);
final long directoryId =
(directory == null ? -1 :
(directory.equals("0") ? Directory.DEFAULT :
(directory.equals("1") ? Directory.LOCAL_INVISIBLE : Long.MIN_VALUE)));

if (directoryId > Long.MIN_VALUE) {
final Cursor cursor = queryLocal(uri, projection, selection, selectionArgs, sortOrder,
directoryId, cancellationSignal);
return addSnippetExtrasToCursor(uri, cursor);
}

DirectoryInfo directoryInfo = getDirectoryAuthority(directory);
if (directoryInfo == null) {
Log.e(TAG, "Invalid directory ID: " + uri);
return null;
}

Builder builder = new Uri.Builder();
builder.scheme(ContentResolver.SCHEME_CONTENT);
builder.authority(directoryInfo.authority);
builder.encodedPath(uri.getEncodedPath());
if (directoryInfo.accountName != null) {
builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, directoryInfo.accountName);
}
if (directoryInfo.accountType != null) {
builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, directoryInfo.accountType);
}

String limit = getLimit(uri);
if (limit != null) {
builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, limit);
}

Uri directoryUri = builder.build();

if (projection == null) {
projection = getDefaultProjection(uri);
}

Cursor cursor;
try {
cursor = getContext().getContentResolver().query(
directoryUri, projection, selection, selectionArgs, sortOrder);
if (cursor == null) {
return null;
}
} catch (RuntimeException e) {
Log.w(TAG, "Directory query failed: uri=" + uri, e);
return null;
}

// Load the cursor contents into a memory cursor (backed by a cursor window) and close the
// underlying cursor.
try {
MemoryCursor memCursor = new MemoryCursor(null, cursor.getColumnNames());
memCursor.fillFromCursor(cursor);
return memCursor;
} finally {
cursor.close();
}
}


在重写query这个方法里,主要是用到了queryLocal这个方法,根据不同的uri去查询对应的表

protected Cursor queryLocal(final Uri uri, final String[] projection, String selection,
String[] selectionArgs, String sortOrder, final long directoryId,
final CancellationSignal cancellationSignal) {

final SQLiteDatabase db = mDbHelper.get().getReadableDatabase();

SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
String groupBy = null;
String having = null;
String limit = getLimit(uri);
boolean snippetDeferred = false;

// The expression used in bundleLetterCountExtras() to get count.
String addressBookIndexerCountExpression = null;

final int match = sUriMatcher.match(uri);
switch (match) {
case SYNCSTATE:
case PROFILE_SYNCSTATE:
return mDbHelper.get().getSyncState().query(db, projection, selection,
selectionArgs, sortOrder);
......
case RAW_CONTACTS:
case PROFILE_RAW_CONTACTS: {
setTablesAndProjectionMapForRawContacts(qb, uri);
break;
}
.......
}


在setTablesAndProjectionMapForRawContacts 设置要查询的表和字段

private void setTablesAndProjectionMapForRawContacts(SQLiteQueryBuilder qb, Uri uri) {
StringBuilder sb = new StringBuilder();
sb.append(Views.RAW_CONTACTS);
qb.setTables(sb.toString()); //设置查询的表为raw_contacts的视图表
qb.setProjectionMap(sRawContactsProjectionMap);
appendAccountIdFromParameter(qb, uri);
}


如果想进一步了解ContactsProvider,可以去看看ContactsProvider的源码,这里提供一个下载google源码镜像的链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: