正在与服务器同步 android 个联系人

Syncing android contacts with server

我正在创建一个 android 应用程序来跟踪保存在设备上的所有联系人(显示在默认 android 联系人应用程序中的联系人)并将它们保存在 MySQL table 在服务器上。

我设法使用 ContectResolver:

读取了所有联系人数据
    //to read only android address book
    String where = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '1'";

    String[] projection = new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.LOOKUP_KEY, ContactsContract.Contacts.HAS_PHONE_NUMBER};

    ContentResolver cr = context.getContentResolver();
    Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, projection, where, null, null);

然后,使用 ContactsContract.Contacts._ID 我查询其他联系人数据:

// Perform a query to retrieve the contact's name parts
        String[] nameProjection = new String[] {
                ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,
                ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME,
                ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME,
                ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME
        };

        Cursor nameCursor = cr.query(
                ContactsContract.Data.CONTENT_URI,
                nameProjection,
                ContactsContract.Data.MIMETYPE + " = '" +
                        ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "' AND " +
                        ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID
                        + " = ?", new String[] { id }, null);

        // Retrieve the name parts
        String firstName = "", middleName = "", lastName = "", displayName = "";
        if(nameCursor.moveToNext()) {
            firstName = nameCursor.getString(nameCursor.getColumnIndex(
                    ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
            middleName = nameCursor.getString(nameCursor.getColumnIndex(
                    ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME));
            lastName = nameCursor.getString(nameCursor.getColumnIndex(
                    ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
            displayName = nameCursor.getString(nameCursor.getColumnIndex(
                    ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME));
        }

然后我将所有这些数据(包括联系人的电子邮件地址和 phone 号码)发送到服务器。

我希望能够像这样定期备份设备的联系人,但能够通过比较旧数据和新数据来检测联系人数据的变化。但是要做到这一点,我需要在 android 设备中的联系人和我保存联系人数据的数据库之间有某种 link。

经过一番搜索,我找到了 3 个选项:

ContactsContract.Contacts._ID
ContactsContract.Contacts.LOOKUP_KEY
ContactsContract.RawContacts._ID

但据我发现,所有这些都不可靠,并且在某些情况下可能会发生变化 - 使我的数据库与设备联系人列表之间的 link 无效。

我考虑过使用 ContentObserver 来检测联系人更改的选项。但是,我希望能够检测到联系人更改,即使我的应用已被卸载,然后某些联系人已更改,然后我的应用已被重新安装。

我可以使用每个联系人的可靠识别码来了解某个联系人何时被更改或删除吗?

编辑:

我现在发现这个变量存在:ContactsContract.ContactsColumns.CONTACT_LAST_UPDATED_TIMESTAMP

问题是它只在 API 级别 18 中引入。我正在研究 min API 15。有什么东西可以替代它以弥补缺少的 API 级别?

恐怕无法知道特定联系人是否发生了变化。因此,您可以在整个地址簿 URI 上注册观察者。这样您就可以在地址簿中的任何内容发生变化时收听。

现在有了观察者,您可以扫描所有联系人并向您的服务器执行 "sync" 数据。

在您的特定情况下,一对 ContactsContract.Contacts._ID 和 ContactsContract.Contacts.LOOKUP_KEY 应该足够可靠。但为了知道是否有任何变化,您需要:

  • 将所有联系人发送到服务器并在服务器上执行同步逻辑(id 和查找密钥应存储在 MySQL 上)
  • 在您的设备(sqllite 数据库、领域、任何其他存储)上保留联系人的本地副本,以避免每次同步时将未更改的联系人发送到服务器