Android系统中的联系人也是通过ContentProvider来对外提供数据的,我们这里实现获取所有联系人、通过电话号码获取联系人、添加联系人、使用事务添加联系人
一.获取所有联系人
1. Android系统中的联系人也是通过ContentProvider来对外提供数据的
2. 数据库路径为:/data/data/com.android.providers.contacts/database/contacts2.db
3. 我们需要关注的有3张表
raw_contacts:其中保存了联系人id
data:和raw_contacts是多对一的关系,保存了联系人的各项数据
mimetypes:为数据类型
4. Provider的authorites为com.android.contacts
5. 查询raw_contacts表的路径为:contacts
6. 查询data表的路径为:contacts/#/data
这个路径为连接查询,要查询“mimetype”字段可以根据“mimetype_id”查询到mimetypes表中的数据
7. 先查询raw_contacts得到每个联系人的id,在使用id从data表中查询对应数据,根据mimetype分类数据
public void testGetAll() { ContentResolver resolver = getContext().getContentResolver(); Uri uri = Uri.parse("content://com.android.contacts/contacts"); Cursor idCursor = resolver.query(uri, new String[] { "_id" }, null, null, null); while (idCursor.moveToNext()) { //获取到raw_contacts表中的id int id = idCursor.getInt(0); //根据获取到的ID查询data表中的数据 uri = Uri.parse("content://com.android.contacts/contacts/" + id + "/data"); Cursor dataCursor = resolver.query(uri, new String[] { "data1", "mimetype" }, null, null, null); StringBuilder sb = new StringBuilder(); sb.append("id=" + id); //查询联系人表中的 while (dataCursor.moveToNext()) { String data = dataCursor.getString(0); String type = dataCursor.getString(1); if ("vnd.android.cursor.item/name".equals(type)) sb.append(", name=" + data); else if ("vnd.android.cursor.item/phone_v2".equals(type)) sb.append(", phone=" + data); else if ("vnd.android.cursor.item/email_v2".equals(type)) sb.append(", email=" + data); } System.out.println(sb); } }
二.存储联系人
public class AddContactAPI5 { public void addContact(Context context, String name, String organisation, String phone, String fax, String email, String address, String website, Bitmap logo) { ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null) .withValue(ContactsContract.RawContacts.AGGREGATION_MODE, ContactsContract.RawContacts.AGGREGATION_MODE_DISABLED) .build()); // add name if (!AppUtils.isBlank(name)) { ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name) .build()); } // add company if (!AppUtils.isBlank(organisation)) { ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, organisation) .withValue(ContactsContract.CommonDataKinds.Organization.TYPE, ContactsContract.CommonDataKinds.Organization.TYPE_WORK) .build()); } // add phone if (!AppUtils.isBlank(phone)) { ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, 1) .build()); } // add Fax if (!AppUtils.isBlank(fax)) { ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, fax) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_FAX_WORK) .build()); } // add email if (!AppUtils.isBlank(email)) { ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Email.DATA, email) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, 1) .build()); } // add address if (!AppUtils.isBlank(address)) { ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, address) .withValue(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK) .build()); } // add website if (!AppUtils.isBlank(website)) { ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Website.URL, website) .withValue(ContactsContract.CommonDataKinds.Website.TYPE, ContactsContract.CommonDataKinds.Website.TYPE_WORK) .build()); } // add logo image Bitmap bm = logo; if (bm != null) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); bm.compress(Bitmap.CompressFormat.PNG, 100, baos); byte[] photo = baos.toByteArray(); if (photo != null) { ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, photo) .build()); } } try { context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); } catch (Exception e) { } } }
android 2.0以上至关重要的一点:
.withValue(ContactsContract.RawContacts.AGGREGATION_MODE, ContactsContract.RawContacts.AGGREGATION_MODE_DISABLED)
加上这句才会把同名联系人分开存储,否则一条联系人调用2次存储后,在对联系人进行edit的时候后报错。这条属性在官方API上都没有说明,很重要。
参考文档:
android 存储联系人(save contact) 总结
Android软件开发之获取通讯录联系人 联系人图像
Android操作联系人
Android 删除手机联系人,添加手机联系人,更新手机联系人信