数据库分析
概述:
mimetype表
该表中的数据主要用作标记,标记data表中的每一条数据是何种数据类型。
此表中的记录内容相对稳定,内容如下:
1. vnd.android.cursor.item/email_v2--邮件
-
vnd.android.cursor.item/im--帐号
-
vnd.android.cursor.item/postal-address_v2--邮政地址
-
vnd.android.cursor.item/photo--图片
-
vnd.android.cursor.item/phone_v2--电话
-
vnd.android.cursor.item/name--姓名
-
vnd.android.cursor.item/organization--公司
-
vnd.android.cursor.item/nickname--昵称
-
vnd.android.cursor.item/group_membership-组别
Contacts表
实际上Contact表不保存联系人的具体数据,具体数据是保存于data表,一个用于保存主数据,一个用于保存子数据(详细数据)。
总结
data、raw_contacts、contacts三个表代表了联系人数据的三种层次。
data里面的一行记录可存储一个联系人信息,如电话号码和email地址。存储于此表的数据类型的集合是开放的,应用程序可以增加自己的数据类型。
raw_contacts的记录表示一个联系人信息,并且可以和一个帐号(account)进行关联(例如,一个gmail帐号)。raw_contacts和打他是一对多的关系。
contacts的记录表示一个或者多个raw_contacts的记录的联合,用于表示用一个联系人的不同联系信息。contacts和raw_contact也是一对多关系。
具体的关系描述从ContactsContract(frameworks/base/core/java/android/provider)中可以看到。
联系人总体代码结构中的如下部分都是与数据库相关的,其中ContactsProvider2是联系人数据提供者,ContactsDatabaseHelper是数据库创建和版本管理的帮助类。
位于frameworks目录下的ContactsContract是联系人数据的描述类,它是联系人数据提供者和应用程序之间的一种约定。它包含了可支持URI和字段信息。
/packages/providers/ContactsProvider/src/com/android/providers/contacts
ContactsDatabaseHelper.java
ContactsProvider2.java
数据相关类—ContactsContract
理解ContactsContract这个类对理解整个联系人数据库至关重要。它不但是对数据库几个表和字段的说明,而且是Contacts provider和应用程序之间的一种约定,它提供了对Contacts provider所支持的URI和各字段的描述。此类可以看作对Contacts2.db这个数据库进行描述的类。
此类的结构非常庞大,整体结构:ContactsContract里面各个内部类分别对应一个数据库表结构,如:Contacts、Data、RawContacts、Group等,而ContactsContract里面同时存在许多接口(Interface),接口之间还有集成关系,用于表示各个字段的定义和组合关系。
数据相关类—ContactsContract$Data
Data作为一个 ContactsContract的一个静态类,继承了DataColumnsWithJoins接口,而DataColumnsWithJoins又继承了DataColumns,DataColumnsWithJoins组合里data表查询时所有可能返回的字段,然后内部类Email实现此字段。Data类图示意图如下:
ContactsContract$CommonDataKinds$Email
data表字段信息位于DataColumns接口定义中,如data1字段对应的DATA1属性,而Email的public static final String ADDRESS=DATA1;是将接口DataColumns中的DATA1属性进行了重新命名而已,对应的表字段还是data1,只不过对于Email而言,data1代表了Email地址。而对于其他类,data1可能表达其他意义,如phone的NUMBER属性也是对应字段data1.这样,在程序中就可以使用Phone.NUMBER这种可读性强的代码。
其他和Email类似的定义有:
Nickname、Organization、Phone、StructuredName、StructuredPostal。这些类都对应data表的某些字段的集合,各自组成了联系人的某类信息。
ContactsProvider2
此类是联系人的数据提供者和操作者,是数据库和应用程序之间的桥梁。
它的代码结构也比较庞大,但从本质上说,它的主要内容就是查询、添加、删除、修改。
1.查询
public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder)
2.增加
public Uri insert(Uri uri,ContentValues values)
如果是批处理的话(运行在事务中),它在基类SQLiteContentProvider的insert会调用自身的protected Uri insertInTransaction(Uri uri,ContentValues values)\
3.删除
public int delete(Uri uri,String selection,String[] selectionArgs)
如果是批处理的话,它会调用
protected int deleteInTransaction(Uri uri,String selection,String[] selectionArgs)
4.更新
public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs)
如果是批处理的话,它会调用
protected int updateInTransaction(Uri uri,ContentValues values,String selection,String[] selectionArgs)
还有一些其他重要函数,不一一列举。
ContactsProvider2与Uri
前面介绍的ContactsProvider2的主要方法里面的地一个参数就是Uri,它通过Uri判断究竟是对哪种类型的数据进行处理,是contacts、raw_contacts还是data,是处理单个记录还是多个记录。它借助UriMatcher这个类对Uri分类进行处理。在类的static静态初始化代码快里面,有如下代码:
static {
// Contacts URI matching table
final UriMatcher matcher = sUriMatcher;
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);
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);
…………
其中CONTACTS、CONTACTS_ID都是实现定义好的常数,用于表示匹配Uri后的标识符。
以uri实际传的值为content://com.android.contacts/contacts/7为例,它被标识为 CONTACTS_ID标识符。
在query、insert(insertInTransaction)、update(updateInTransaction)、delete(deleteInTransaction)里面。有如下语句:
final int match = sUriMatcher.match(uri);
switch (match) {
……
case CONTACTS: {
// TODO
return 0;
}
case CONTACTS_ID: {
……
}
case CONTACTS_ID之后是具体的处理代码
如果是查询,则删除的是_id为7的联系人信息
如果是删除,则删除_id为7的联系人信息
如果是更新,则更新_id为7的联系人数据