一,联系人数据库
联系人数据库路径:/data/data/com.android.providers.contacts/databases/contact2.db
联系人数据库中的表非常多,但实际要用到的比较重要的有4张表:contacts、data、mimetypes和raw_contacts
1、contacts表
display_name: 联系人名称
photo_id:头像的ID,如果没有设置联系人头像,这个字段就为空
times_contacted:通话记录的次数
last_time_contacted: 最后的通话时间
lookup :是一个持久化的储存,因为用户可能会改名,但是它改不了lookup
该表保存了本机保存的所有联系人,每个联系人占一行,该表保存了联系人的ContactID、联系次数、最后一次联系的时间、是否含有号码、是否被添加到收藏夹等信息
2、data表
raw_contact_id:通过raw_contact_id可以找到 raw_contact表中相对的数据。
data1 到 data15 这里保存着联系人的信息 联系人名称 联系人电话号码 电子邮件 备注 等等。
该表保存了所有创建过的手机测联系人的所有信息,每个字段占一行 ,该表保存了两个ID: MimeTypeID和RawContactID,从而将data表和raw_contacts表联系起来。联系人的所有信息保存在列data1至data15中,各列中保存的内容根据MimeTypeID的不同而不同。如保存号码(MimeTypeID=5)的那行数据中,data1列保存号码,data2列保存号码类型(手机号码、家庭号码、工作号码等)
3、mimetypes
该表定义的各个联系人字段的唯一标志,及联系人信息的类别标志
4、raw_contacts
version :版本号,用于监听变化
deleted :删除标志, 0为默认 1 表示这行数据已经删除
display_name : 联系人名称
last_time_contacts : 最后联系的时间
该表保存了所有创建过的手机联系人,包括已经删除的联系人、每个联系人占一行,表里有一列标识该联系人是否被删除,该表保存了两个ID: RawContactID和ContactID,从而将contacts表和raw_contacts表联系起来。该表保存了联系人的RawContactID、ContactID、联系次数、最后一次联系的时间、是否被添加到收藏夹、显示的名字、用于排序的汉语拼音等信息
二、关于操作联系人数据库
对于换机类型的应用,最重要的是联系人数据、短信数据和通话记录数据的迁移,需要进行读取和写入操作
1、读取联系人数据
正常可以在读取之前按照各个联系人来读取各个表中的数据,还有比较简便的方法,直接读取每个表,这种方法也是不会对之后写入数据库造成影响,在需要获取手机中联系人数量时,要获取contacts表的数量而不是raw_contacts表
public int getContactsCount() {
ArrayList<DataInfo> rawList = new ArrayList<>();
ContentResolver resolver = MainApplication.getContext().getContentResolver();
// final Cursor c = resolver.query(ContactsContract.RawContacts.CONTENT_URI, null, null, null, null);
final Cursor c = resolver.query(ContactsContract.Contacts.CONTENT_URI,null,null,null,null);
int contactsCount = c.getCount();
Log.d(TAG, "getContactsCount: " + contactsCount);
return contactsCount;
}
2、写入数据库
在写入时,无需对各个联系人信息按照每个联系人进行写入,直接向相关表中插入数据,后续再实现表的关联
public static void addContact(ArrayList<DataInfo> sdatas, int offset) {
if (sdatas == null || sdatas.size() == 0) {
return;
}
ContentValues mValues = new ContentValues();
//首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获得系统返回的rawContactId
Uri rawContactUri = MainApplication.getContext().getContentResolver().insert(ContactsContract.RawContacts.CONTENT_URI, mValues);
long rawContactId = ContentUris.parseId(rawContactUri);
long common_id = sdatas.get(offset).raw_contact_id;//SData数据里的raw_contact_id
for (int i = offset; i < sdatas.size(); i++) {
mValues.clear();
DataInfo sdata = sdatas.get(i);
//判断这些sdata是否属于同一个联系人
if (sdata.raw_contact_id == common_id) {
// 向data表插入数据
mValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);//插入上面获取到的raw_contact_id
if (sdata.is_primary != 0) {
mValues.put(ContactsContract.Data.IS_PRIMARY, sdata.is_primary);
}
if (!TextUtils.isEmpty(sdata.mimetype)) {
mValues.put(ContactsContract.Data.MIMETYPE, sdata.mimetype);
}
if (sdata.is_surper_primary != 0) {
mValues.put(ContactsContract.Data.IS_SUPER_PRIMARY, sdata.is_surper_primary);
}
if (sdata.data_version != 0) {
mValues.put(ContactsContract.Data.DATA_VERSION, sdata.data_version);
}
if (!TextUtils.isEmpty(sdata.data1)) {
mValues.put(ContactsContract.Data.DATA1, sdata.data1);
}
if (!TextUtils.isEmpty(sdata.data2)) {
mValues.put(ContactsContract.Data.DATA2, sdata.data2);
}
if (sdata.mimetype.equals(DataInfo.LOCA_GROUP_TYPE)) {
mValues.put(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID, sdata.data1);
} else if (sdata.mimetype.equals(DataInfo.LOCA_NAME)) {
mValues.put(ContactsContract.Data.DATA2, sdata.data1);
} else if (sdata.mimetype.equals(ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE)) {
if (map.get(sdata.data1) != null) {
//根据原来的groupId获取最新的groupId
String groupId = (String) map.get(sdata.data1);
mValues.put(ContactsContract.Data.DATA1, groupId);
}
}
if (!TextUtils.isEmpty(sdata.data3)) {
mValues.put(ContactsContract.Data.DATA3, sdata.data3);
}
if (!TextUtils.isEmpty(sdata.data4)) {
mValues.put(ContactsContract.Data.DATA4, sdata.data4);
}
if (!TextUtils.isEmpty(sdata.data5)) {
mValues.put(ContactsContract.Data.DATA5, sdata.data5);
}
if (!TextUtils.isEmpty(sdata.data6)) {
mValues.put(ContactsContract.Data.DATA6, sdata.data6);
}
if (!TextUtils.isEmpty(sdata.data7)) {
mValues.put(ContactsContract.Data.DATA7, sdata.data7);
}
if (!TextUtils.isEmpty(sdata.data8)) {
mValues.put(ContactsContract.Data.DATA8, sdata.data8);
}
if (!TextUtils.isEmpty(sdata.data9)) {
mValues.put(ContactsContract.Data.DATA9, sdata.data9);
}
if (!TextUtils.isEmpty(sdata.data10)) {
mValues.put(ContactsContract.Data.DATA10, sdata.data10);
}
if (!TextUtils.isEmpty(sdata.data11)) {
mValues.put(ContactsContract.Data.DATA11, sdata.data11);
}
if (!TextUtils.isEmpty(sdata.data12)) {
mValues.put(ContactsContract.Data.DATA12, sdata.data12);
}
if (!TextUtils.isEmpty(sdata.data13)) {
mValues.put(ContactsContract.Data.DATA13, sdata.data13);
}
if (!TextUtils.isEmpty(sdata.data14)) {
mValues.put(ContactsContract.Data.DATA14, sdata.data14);
}
if (!TextUtils.isEmpty(sdata.data_sync1)) {
mValues.put(ContactsContract.Data.SYNC1, sdata.data_sync1);
}
if (!TextUtils.isEmpty(sdata.data_sync2)) {
mValues.put(ContactsContract.Data.SYNC2, sdata.data_sync2);
}
if (!TextUtils.isEmpty(sdata.data_sync3)) {
mValues.put(ContactsContract.Data.SYNC3, sdata.data_sync3);
}
if (!TextUtils.isEmpty(sdata.data_sync4)) {
mValues.put(ContactsContract.Data.SYNC4, sdata.data_sync4);
}
MainApplication.getContext().getContentResolver().insert(ContactsContract.Data.CONTENT_URI, mValues);
}
//
else {
//使用嵌套
addContact(sdatas, i);
break; //进入嵌套的同时记得结束for循环!!!
}
}
}
该方法中sdata.raw_contact_id 和 common_id都是旧手机的rawContactsId,仅仅是用来判断当前插入的联系人是否为同一个联系人的数据,而关于实际raw_contact_id的插入要写入新手机实际的新的raw_contact_id,这样才能实现数据关联,获取实际新手机中的rawContactsId:
ContentValues mValues = new ContentValues();
//首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获得系统返回的rawContactId
Uri rawContactUri = MainApplication.getContext().getContentResolver().insert(ContactsContract.RawContacts.CONTENT_URI, mValues);
long rawContactId = ContentUris.parseId(rawContactUri);
使用嵌套循环方式插入全部数据,这种处理方法,仅适用于小量数据时,在需要操作大量数据,建议使用批量插入操作
写入联系人分组时,同样需要获取新手机实际的groupId,方法思路基本和写入联系人差不多
public static void addGroups(ArrayList<GroupInfo> sGroups) {
if (sGroups == null || sGroups.size() == 0) {
return;
}
ContentValues mValues = new ContentValues();
for (int i = 0; i < sGroups.size(); i++) {
mValues.clear();
GroupInfo sGroup = sGroups.get(i);
mValues.put(ContactsContract.Groups.TITLE, sGroup.title);
//首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获得系统返回的rawContactId
Uri groupUri = MainApplication.getContext().getContentResolver().insert(ContactsContract.Groups.CONTENT_URI, mValues);
long newGroupId = ContentUris.parseId(groupUri);
// mValues.put(Groups._ID, groupId);//插入上面获取到的_id
// SGroup sGroup = sGroups.get(i);
// // 向表插入数据
// if (!TextUtils.isEmpty(sGroup.sourceid)) {
// mValues.put(Groups.SOURCE_ID, sGroup.sourceid);
// }
// if (sGroup.dirty != 0) {
// mValues.put(Groups.DIRTY, sGroup.dirty);
// }
// if (!TextUtils.isEmpty(sGroup.title)) {
// mValues.put(Groups.TITLE, sGroup.title);
// }
// if (sGroup.version != 0) {
// mValues.put(Groups.VERSION, sGroup.version);
// }
// context.getContentResolver().insert(Groups.CONTENT_URI, mValues);
map.put(sGroup.id + "", newGroupId + ""); //关联原有的groupId与新的groupId,添加联系人时替换
}
}
private static void inPutContactsDB() {
String contactPath = getFilePath(CONTACTS_DIRECTORY, CONTACT_PATH_DIR);
String groupPath = getFilePath(CONTACTS_DIRECTORY, GROUP_PATH_DIR);
// File contactFile =new File(ContactPath);
//导入文件到数据库
final HashMap<String, Object> contactResult = FileUtils.importFile(contactPath, DataInfo.class);
final HashMap<String, Object> groupResult = FileUtils.importFile(groupPath, GroupInfo.class);
new Thread(new Runnable() {
@Override
public void run() {
//写入数据库
//1.写入
// Log.e(TAG, "1.写入联系人组");
addGroups((ArrayList<GroupInfo>) groupResult.get(GroupInfo.class.getSimpleName()));
// Log.e(TAG, "2.写入联系人");
addContact((ArrayList<DataInfo>) contactResult.get(DataInfo.class.getSimpleName()), 0);
// if(file.delete()){
// Log.e(TAG, "删除临时文件contact.txt");
// }else {
// Log.e(TAG, "删除临时文件失败!");
// }
}
}).start();
}