最近做了一个拉取用户通讯录的App,其中关键点在于用户通讯录的拉取和还原,所以根据业务需求抽象出来一个工具类,其中也遇到坑,但是还是算比较顺利的完成了。
<!-- 读联系人权限 -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<!-- 写联系人权限 -->
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
package com.fenla.contacts.utils;
import android.app.Activity;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.os.RemoteException;
import android.provider.ContactsContract;
import com.fenla.contacts.model.bean.ContactBean;
import java.util.ArrayList;
import java.util.List;
/**
*
* 联系人的备份和还原工具类
*/
public class ContactUtils {
public static String[] projection = new String[]{
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.Contacts.DISPLAY_NAME};
/**
* 获取联系人数据
*
* @param activity
* @return
*/
public static List<ContactBean> getContactsData(Activity activity) {
Cursor cursor = null;
String contactName;
String contactNumber;
ContentResolver resolver = activity.getContentResolver();
List<ContactBean> list = new ArrayList<>();
//搜索字段
try {
cursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
//获取联系人的ID
int contactId = cursor.getInt(0);
//获取联系人的姓名
contactName = cursor.getString(2);
//获取联系人的号码
contactNumber = cursor.getString(1);
ContactBean bean = new ContactBean();
bean.setContactNo(contactNumber);
bean.setContactName(contactName);
list.add(bean);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return list;
}
/**
* 还原通讯录
*
* @param activity
* @param list
*/
public static void restoreContactsData(Activity activity, List<ContactBean> list) {
// 需要批量插入的数据
List<ContactBean> beanList = new ArrayList<>();
for (ContactBean contactBean : list) {
contactBean.setContactName(contactBean.getContactName().replace("-",""));
}
ContentResolver resolver = activity.getContentResolver();
for (ContactBean contactBean : list) {
boolean flag = hasExist(resolver, contactBean.getContactName(), contactBean.getContactNo());
if (!flag) {
beanList.add(contactBean);
}
}
if (beanList.size() != 0) {
copyAllPhone(beanList, activity);
}
}
/**
* 判断是否存在这个联系人
*
* @param resolver
* @param name
* @param phone
* @return
*/
public static boolean hasExist(ContentResolver resolver, String name, String phone) {
Cursor cursor = null;
String contactName;
String contactNumber;
//搜索字段
try {
cursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
//获取联系人的ID
int contactId = cursor.getInt(0);
//获取联系人的姓名
contactName = cursor.getString(2);
//获取联系人的号码
contactNumber = cursor.getString(1);
if (contactName.equals(name) && contactNumber.equals(phone)) {
return true;
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return false;
}
/**
* 批量插入联系人
*
* @param list
* @param ctx
*/
public static void copyAllPhone(List<ContactBean> list, Activity ctx) {
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
int rawContactInsertIndex;
for (int i = 0; i < list.size(); i++) {
rawContactInsertIndex = ops.size();//这句好很重要,有了它才能给真正的实现批量添加。
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
.withYieldAllowed(true)
.build());
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID,
rawContactInsertIndex)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, list.get(i).getContactName())
.withYieldAllowed(true)
.build());
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactInsertIndex)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, list.get(i).getContactNo())
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
.withYieldAllowed(true)
.build());
}
try {
// 批量添加
ctx.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException e) {
e.printStackTrace();
} catch (OperationApplicationException e) {
e.printStackTrace();
}
}
}
几个关键节点需要注意的:
1、因为我有做简单的号码比对,所以过程中出现的问题是一直都是单条插入,和动态获取插入后的联系人数据,使插入的效率太低,然后我通过批量插入的方式来操作,明显减少了插入时间。
2、在通讯录的插入和拉取的时候都要用RxJava2来开IO线程来操作,不然当数据量大的时候,主线程被卡住,会出现ANR。