You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android(Java)如何仅查询已更新姓名/手机号的联系人?

仅查询姓名或手机号更新的Android联系人方案

要实现仅获取姓名或手机号字段更新的联系人,核心思路是通过记录上次同步时间戳过滤更新数据,并利用ContentObserver的精准回调缩小查询范围,具体实现如下:

核心逻辑

  • 利用ContactsContract.Contacts.CONTACT_LAST_UPDATED_TIMESTAMP字段判断联系人最后更新时间
  • 通过重载ContentObserver的onChange(boolean selfChange, Uri uri)方法,获取变动联系人的精准URI,避免全量查询
  • 用SharedPreferences存储上次同步时间,过滤出时间戳晚于该值的联系人

代码实现

1. 同步时间戳的存储与读取

// 获取上次同步时间,初始值为应用启动时间
private long getLastSyncTime() {
    SharedPreferences sp = getSharedPreferences("ContactSync", MODE_PRIVATE);
    return sp.getLong("last_sync_time", System.currentTimeMillis());
}

// 更新同步时间为当前时间
private void updateLastSyncTime() {
    SharedPreferences sp = getSharedPreferences("ContactSync", MODE_PRIVATE);
    sp.edit().putLong("last_sync_time", System.currentTimeMillis()).apply();
}

2. 优化ContentObserver回调

class ContactObserver extends ContentObserver {
    public ContactObserver(Handler handler) {
        super(handler);
    }

    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        contactChanged(null); // 无具体URI时执行时间过滤查询
    }

    @Override
    public void onChange(boolean selfChange, Uri uri) {
        super.onChange(selfChange, uri);
        contactChanged(uri); // 传入变动URI,精准查询单个联系人
    }
}

3. 修改查询逻辑,实现精准过滤

public void contactChanged(Uri changedUri) {
    ContentResolver contentResolver = getContentResolver();
    long lastSyncTime = getLastSyncTime();
    
    String[] PROJECTION = new String[]{
            ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
            ContactsContract.Contacts.DISPLAY_NAME,
            ContactsContract.CommonDataKinds.Phone.NUMBER,
            ContactsContract.Contacts.CONTACT_LAST_UPDATED_TIMESTAMP // 新增更新时间字段
    };

    Cursor cursor = null;
    try {
        if (changedUri != null) {
            // 有变动URI时,直接查询该联系人
            cursor = contentResolver.query(changedUri, PROJECTION, null, null, null);
        } else {
            // 无URI时,过滤出上次同步后更新的联系人
            String selection = ContactsContract.Contacts.CONTACT_LAST_UPDATED_TIMESTAMP + " > ?";
            String[] selectionArgs = new String[]{String.valueOf(lastSyncTime)};
            cursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                    PROJECTION, selection, selectionArgs, null);
        }

        JSONArray contactsArray = new JSONArray();
        if (cursor != null && cursor.moveToFirst()) {
            do {
                String id = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
                String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));

                JSONObject contact = new JSONObject();
                contact.put("id", id);
                contact.put("name", name);
                contact.put("number", number);

                contactsArray.put(contact);
            } while (cursor.moveToNext());
        }

        getUpdatedContacts(contactsArray.toString(), pointer);
        updateLastSyncTime(); // 更新同步时间戳
    } catch (JSONException e) {
        e.printStackTrace();
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
}

4. 注册ContentObserver

getContentResolver().registerContentObserver(
        ContactsContract.Contacts.CONTENT_URI,
        true, // 监听子表变动(如手机号表)
        new ContactObserver(new Handler(Looper.getMainLooper()))
);

额外说明

如果需要严格仅过滤姓名或手机号的变动(排除头像、备注等其他字段更新),还需在本地存储每个联系人的历史姓名和手机号,查询到更新的联系人后,对比这两个字段是否真的发生变化,再纳入结果集。

内容的提问来源于stack exchange,提问作者yeri123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 22:53:10