需求

由于项目需要所以在app登录之后都有获取一份本地的通讯录然后上传到服务器。但是最近后台的小伙伴一直反馈说如果每次前端都把整个的通讯录上传过去,然后后台再做比较、去重、再插入数据库的话这样给服务器的压力会比较大。仔细一想其实也是,如果用户的通讯录没有改变那么上诉的所有操作都是白费的。

于是我们前端要做到除了用户第一次全部上传外,以后只有在通讯录发生改变的时候才上传修改的部分通讯录。

为了实现以上的需求我们需要实现下面几个功能:

首次登录上传全部通讯录,然后保存通讯录到本地数据库中

监听联系人是否改变

如果联系人发生改变,获取到改变后的联系人和之前保存在本地的做比较得到改变后的,然后上传服务器

首次全部上传,并且保存到本地数据库中

第一次上传的时候获取全部联系人数据,上传完成后保存到greenDao中,这里主要记录连个字段,RawContacts._ID和RawContacts.VERSION。

RawContacts._ID:用于判断这个联系人之前是否存在

RawContacts.VERSION:当新创建一个联系人的时候version的默认值为2,以后每修改一次就增加1,所以它是判断联系人是否修改的关键

ContentResolver _contentResolver = getContentResolver();
Cursor cursor = _contentResolver.query(
ContactsContract.RawContacts.CONTENT_URI, null, null, null,
null);
//清空本地数据库
oldContactLists.clear();
DBHelper.getInstance().getContact2Dao().deleteAll();
while (cursor.moveToNext()) {
Long contactID = cursor.getLong(cursor
.getColumnIndex(ContactsContract.RawContacts._ID));
long contactVersion = cursor.getLong(cursor
.getColumnIndex(ContactsContract.RawContacts.VERSION));
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
Contact2 contact2 = new Contact2();
contact2.vesion = contactVersion;
contact2.name = name;
contact2.phone = getPhoneNumber(contactID);
contact2.contactID = contactID;
contact2.cid = MyApplication.userAllInfo.cid;
oldContactLists.add(contact2);
}
cursor.close();
upLoad(oldContactLists);
下面是模拟上传代码成功后保存通讯录到greenDao中:
Log.e("+++","上传成功");
Contact2Dao contact2Dao = DBHelper.getInstance().getContact2Dao();
for (int i = 0; i < removeDuplicateContactLists1.size(); i++) {
Log.e("+++","上传了:"+removeDuplicateContactLists1.get(i).name+" "+removeDuplicateContactLists1.get(i).phone);
contact2Dao.insert(removeDuplicateContactLists1.get(i));
}

接下来开始就是要开启一个service去监听联系人的变化

在service启动的时候:

getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contactObserver);
/**
* 监听通讯录变化
*/
private ContentObserver contactObserver = new ContentObserver(new Handler()) {
@Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
boolean needUpdate = isContactChanged();
if (needUpdate) {
upLoad(newContactLists);
getContentResolver().unregisterContentObserver(contactObserver);
needUpdate = false;
}
}
};

当监听到通讯录有改变的时候就调用isContactChanged()方法去判断联系人是否有修改

/**

* 判断是否有改变
*
* @return
*/
public boolean isContactChanged() {
boolean theReturn = false;
ContentResolver _contentResolver = getContentResolver();
Cursor cursor = _contentResolver.query(
ContactsContract.RawContacts.CONTENT_URI, null, null, null,
null);
String phoneNumber = null;
newContactLists.clear();
//当前获取到的最新通讯录
List tempLists = new ArrayList<>();
while (cursor.moveToNext()) {
Long contactID = cursor.getLong(cursor
.getColumnIndex(ContactsContract.RawContacts._ID));
long contactVersion = cursor.getLong(cursor
.getColumnIndex(ContactsContract.RawContacts.VERSION));
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
Contact2 contact2 = new Contact2();
contact2.vesion = contactVersion;
contact2.name = name;
contact2.contactID = contactID;
contact2.cid = MyApplication.userAllInfo.cid;
tempLists.add(contact2);
}
cursor.close();
//最新的通讯录去重
for (int i = 0; i < tempLists.size(); i++) {
for (int j = tempLists.size() - 1; j > i; j--) {
if (tempLists.get(j).name.equals(tempLists.get(i).name)) {
tempLists.remove(j);
}
}
}
//本地数据库老的通讯录id
List ids = new ArrayList<>();
for (int i = 0; i < oldContactLists.size(); i++) {
ids.add(oldContactLists.get(i).contactID);
}
for (int i = 0; i < tempLists.size(); i++) {
//联系人之前存在
Long contactID = tempLists.get(i).contactID;
int index = ids.indexOf(contactID);
if (ids.contains(contactID)) {
//老的version
long version = oldContactLists.get(index).vesion;
//version和之前保存的不一致,联系人被修改
if (version != tempLists.get(i).vesion) {
phoneNumber = getPhoneNumber(contactID);
Contact2 contact2 = new Contact2();
contact2.vesion = tempLists.get(i).vesion;
contact2.name = tempLists.get(i).name;
contact2.phone = phoneNumber;
contact2.contactID = tempLists.get(i).contactID;
contact2.cid = MyApplication.userAllInfo.cid;
newContactLists.add(contact2);
theReturn = true;
}
} else {
//联系人不存在,新增
phoneNumber = getPhoneNumber(contactID);
Contact2 contact2 = new Contact2();
contact2.vesion = tempLists.get(i).vesion;
contact2.name = tempLists.get(i).name;
contact2.phone = phoneNumber;
contact2.contactID = tempLists.get(i).contactID;
contact2.cid = MyApplication.userAllInfo.cid;
newContactLists.add(contact2);
theReturn = true;
}
}
return theReturn;
}

最终newContactLists中的数据就是修改后的联系人。但是有一点需要注意,之前都是使用的RawContacts中的数据,但是这个表里面只能回去到联系人的RawContacts.id,RawContacts.version等数据,并不能获取到用户的电话号码。所以我们必须要根据RawContacts.id去得到用户的电话号码。

/**
* 根据contactID得到联系人号码
*
*@param contactID
*@return
*/
private String getPhoneNumber(Long contactID) {
Uri rawContactUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, contactID);
Uri entityUri = Uri.withAppendedPath(rawContactUri, ContactsContract.RawContacts.Entity.CONTENT_DIRECTORY);
Cursor c = getContentResolver().query(entityUri,
new String[]{ContactsContract.RawContacts.SOURCE_ID, ContactsContract.Contacts.Entity.DATA_ID, ContactsContract.RawContacts.Entity.MIMETYPE, ContactsContract.Contacts.Entity.DATA1},
null, null, null);
try {
while (c.moveToNext()) {
if (!c.isNull(1)) {
String data = c.getString(3);
return data;
}
}
} finally {
c.close();
}
return "";
}
至此,已经能够实现监听联系人变化,然后获取到变化后的联系人的姓名和电话号码。
下面贴出完整的代码,只需要把其中的上传联系人部分替换掉就能够完整使用,当然这里面greenDao部分需要自己去实现。
public class ContactIntentService extends IntentService {
//原始的
private List oldContactLists;
//修改的
private List newContactLists;
public ContactIntentService() {
super("contactIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
}
@Override
public void onCreate() {
super.onCreate();
DBHelper.init(this);
oldContactLists = new ArrayList<>();
newContactLists = new ArrayList<>();
initHashMap();
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contactObserver);
}
/**
* 监听通讯录变化
*/
private ContentObserver contactObserver = new ContentObserver(new Handler()) {
@Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
boolean needUpdate = isContactChanged();
if (needUpdate) {
upLoad(newContactLists);
getContentResolver().unregisterContentObserver(contactObserver);
needUpdate = false;
}
}
};
/**
* 记录下RawContacts._ID和对应的version
*/
public void initHashMap() {
//如果本地数据库没有数据,上传全部通讯录
if (DBHelper.getInstance().getContact2Dao().queryBuilder().list() == null
|| DBHelper.getInstance().getContact2Dao().queryBuilder().list().size() <= 0) {
ContentResolver _contentResolver = getContentResolver();
Cursor cursor = _contentResolver.query(
ContactsContract.RawContacts.CONTENT_URI, null, null, null,
null);
//清空本地数据库
oldContactLists.clear();
DBHelper.getInstance().getContact2Dao().deleteAll();
while (cursor.moveToNext()) {
Long contactID = cursor.getLong(cursor
.getColumnIndex(ContactsContract.RawContacts._ID));
long contactVersion = cursor.getLong(cursor
.getColumnIndex(ContactsContract.RawContacts.VERSION));
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
Contact2 contact2 = new Contact2();
contact2.vesion = contactVersion;
contact2.name = name;
contact2.phone = getPhoneNumber(contactID);
contact2.contactID = contactID;
contact2.cid = MyApplication.userAllInfo.cid;
oldContactLists.add(contact2);
}
cursor.close();
//去掉重复,因为上面在遍历的时候会循环添加3次
for (int i = 0; i < oldContactLists.size(); i++) {
for (int j = oldContactLists.size() - 1; j > i; j--) {
if (oldContactLists.get(j).name.equals(oldContactLists.get(i).name)) {
oldContactLists.remove(j);
}
}
}
Log.e("+++", "原始通讯录人数:" + oldContactLists.size());
upLoad(oldContactLists);
} else {
//本地数据库有数据和本地数据库比较后上传修改和增加的联系人信息
oldContactLists.addAll(DBHelper.getInstance().getContact2Dao().queryBuilder().list());
}
}
private void upload( final List removeDuplicateContactLists1) {
Log.e("+++","上传成功");
Contact2Dao contact2Dao = DBHelper.getInstance().getContact2Dao();
for (int i = 0; i < removeDuplicateContactLists1.size(); i++) {
Log.e("+++","上传了:"+removeDuplicateContactLists1.get(i).name+" "+removeDuplicateContactLists1.get(i).phone);
contact2Dao.insert(removeDuplicateContactLists1.get(i));
}
getContentResolver().unregisterContentObserver(contactObserver);
}
}
/**
* 判断是否有改变
*
*@return
*/
public boolean isContactChanged() {
boolean theReturn = false;
ContentResolver _contentResolver = getContentResolver();
Cursor cursor = _contentResolver.query(
ContactsContract.RawContacts.CONTENT_URI, null, null, null,
null);
String phoneNumber = null;
newContactLists.clear();
//当前获取到的最新通讯录
List tempLists = new ArrayList<>();
while (cursor.moveToNext()) {
Long contactID = cursor.getLong(cursor
.getColumnIndex(ContactsContract.RawContacts._ID));
long contactVersion = cursor.getLong(cursor
.getColumnIndex(ContactsContract.RawContacts.VERSION));
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
Contact2 contact2 = new Contact2();
contact2.vesion = contactVersion;
contact2.name = name;
contact2.contactID = contactID;
contact2.cid = MyApplication.userAllInfo.cid;
tempLists.add(contact2);
}
cursor.close();
//最新的通讯录去重
for (int i = 0; i < tempLists.size(); i++) {
for (int j = tempLists.size() - 1; j > i; j--) {
if (tempLists.get(j).name.equals(tempLists.get(i).name)) {
tempLists.remove(j);
}
}
}
//本地数据库老的通讯录id
List ids = new ArrayList<>();
for (int i = 0; i < oldContactLists.size(); i++) {
ids.add(oldContactLists.get(i).contactID);
}
for (int i = 0; i < tempLists.size(); i++) {
//联系人之前存在
Long contactID = tempLists.get(i).contactID;
int index = ids.indexOf(contactID);
if (ids.contains(contactID)) {
//老的version
long version = oldContactLists.get(index).vesion;
//version和之前保存的不一致,联系人被修改
if (version != tempLists.get(i).vesion) {
phoneNumber = getPhoneNumber(contactID);
Contact2 contact2 = new Contact2();
contact2.vesion = tempLists.get(i).vesion;
contact2.name = tempLists.get(i).name;
contact2.phone = phoneNumber;
contact2.contactID = tempLists.get(i).contactID;
contact2.cid = MyApplication.userAllInfo.cid;
newContactLists.add(contact2);
theReturn = true;
}
} else {
//联系人不存在,新增
phoneNumber = getPhoneNumber(contactID);
Contact2 contact2 = new Contact2();
contact2.vesion = tempLists.get(i).vesion;
contact2.name = tempLists.get(i).name;
contact2.phone = phoneNumber;
contact2.contactID = tempLists.get(i).contactID;
contact2.cid = MyApplication.userAllInfo.cid;
newContactLists.add(contact2);
theReturn = true;
}
}
return theReturn;
}
/**
* 根据contactID得到联系人号码
*
*@param contactID
*@return
*/
private String getPhoneNumber(Long contactID) {
Uri rawContactUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, contactID);
Uri entityUri = Uri.withAppendedPath(rawContactUri, ContactsContract.RawContacts.Entity.CONTENT_DIRECTORY);
Cursor c = getContentResolver().query(entityUri,
new String[]{ContactsContract.RawContacts.SOURCE_ID, ContactsContract.Contacts.Entity.DATA_ID, ContactsContract.RawContacts.Entity.MIMETYPE, ContactsContract.Contacts.Entity.DATA1},
null, null, null);
try {
while (c.moveToNext()) {
if (!c.isNull(1)) {
String data = c.getString(3);
return data;
}
}
} finally {
c.close();
}
return "";
}
}