联系人合并流程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/michael_yt/article/details/78345560

本博客基于android7.1版本分析,仅用于沟通学习使用

整体流程总结

  1. 通过在ContactEditorBaseFragment中对option item link的点击跳转到ContactSelectionActivity界面
  2. 通过LoaderManager去查询contactsprovider中的数据,并分成两部分显示数据
  3. 上半部分显示系统建议合并的联系人最多显示4个,根据联系人的名字、电话号码和邮件是否相同来显示建议合并的联系人
  4. 下半部分显示当前数据库所有的联系人
  5. 当选定需要合并的联系人后,会判读当前联系人内容是否发生过改变,如果改变了就显示JoinContactConfirmationDialogFragment的dialog
  6. 通过ContactSaveService,它继承自IntentService,通过异步的方式去更新数据库信息
  7. 最后会使用第一个联系人的名字作为合并后联系人的名字

整体操作流程

这里写图片描述

合并前后数据库部分变化

这里写图片描述

整体流程图

这里写图片描述

部分重要方法说明

JoinContactListAdapter

@Override
    public void configureLoader(CursorLoader cursorLoader, long directoryId) {
        JoinContactLoader loader = (JoinContactLoader) cursorLoader;
        ...............

        builder.appendQueryParameter("limit", String.valueOf(MAX_SUGGESTIONS));//MAX_SUGGESTIONS=4
        builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE,
                SimContactsConstants.ACCOUNT_TYPE_SIM);
        builder.appendQueryParameter(SimContactsConstants.WITHOUT_SIM_FLAG,
                "true");
        loader.setSuggestionUri(builder.build());//将构建好的查询suggestion联系人的uri放进loader中

        // TODO simplify projection
        loader.setProjection(getProjection(false));
        final Uri allContactsUri;
        if (!TextUtils.isEmpty(filter)) {
            allContactsUri = buildSectionIndexerUri(Contacts.CONTENT_FILTER_URI).buildUpon()
                .appendEncodedPath(Uri.encode(filter))
                .appendQueryParameter(
                        ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT))
                    .appendQueryParameter(RawContacts.ACCOUNT_TYPE,
                            SimContactsConstants.ACCOUNT_TYPE_SIM)
                    .appendQueryParameter(
                            SimContactsConstants.WITHOUT_SIM_FLAG, "true")
                .build();
        } else {
            allContactsUri = buildSectionIndexerUri(Contacts.CONTENT_URI).buildUpon()
                .appendQueryParameter(
                        ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT))
                    .appendQueryParameter(RawContacts.ACCOUNT_TYPE,
                            SimContactsConstants.ACCOUNT_TYPE_SIM)
                    .appendQueryParameter(
                            SimContactsConstants.WITHOUT_SIM_FLAG, "true")
                .build();
        }
        loader.setUri(allContactsUri); //将查询所有联系人的uri放进loader中
        .....
    }

ContactSaveService

    private void joinContacts(Intent intent) {
        long contactId1 = intent.getLongExtra(EXTRA_CONTACT_ID1, -1);
        long contactId2 = intent.getLongExtra(EXTRA_CONTACT_ID2, -1);

        // Load raw contact IDs for all raw contacts involved - currently edited and selected
        // in the join UIs.
        long rawContactIds[] = getRawContactIdsForAggregation(contactId1, contactId2);
        if (rawContactIds == null) {
            Log.e(TAG, "Invalid arguments for joinContacts request");
            return;
        }

        ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();

        // For each pair of raw contacts, insert an aggregation exception
        for (int i = 0; i < rawContactIds.length; i++) {
            for (int j = 0; j < rawContactIds.length; j++) {
                if (i != j) {
                    buildJoinContactDiff(operations, rawContactIds[i], rawContactIds[j]);//构建插入agg_exception表的数据
                }
            }
        }

        final ContentResolver resolver = getContentResolver();

        // Use the name for contactId1 as the name for the newly aggregated contact.
        final Uri contactId1Uri = ContentUris.withAppendedId(
                Contacts.CONTENT_URI, contactId1); //使用第一个联系人的名字
        final Uri entityUri = Uri.withAppendedPath(
                contactId1Uri, Contacts.Entity.CONTENT_DIRECTORY);
        Cursor c = resolver.query(entityUri,
                ContactEntityQuery.PROJECTION, ContactEntityQuery.SELECTION, null, null);
        if (c == null) {
            Log.e(TAG, "Unable to open Contacts DB cursor");
            showToast(R.string.contactSavedErrorToast);
            return;
        }
        long dataIdToAddSuperPrimary = -1;
        try {
            if (c.moveToFirst()) {
                dataIdToAddSuperPrimary = c.getLong(ContactEntityQuery.DATA_ID);
            }
        } finally {
            c.close();
        }

        // Mark the name from contactId1 IS_SUPER_PRIMARY to make sure that the contact
        // display name does not change as a result of the join.
        if (dataIdToAddSuperPrimary != -1) {
            Builder builder = ContentProviderOperation.newUpdate(
                    ContentUris.withAppendedId(Data.CONTENT_URI, dataIdToAddSuperPrimary));
            builder.withValue(Data.IS_SUPER_PRIMARY, 1);
            builder.withValue(Data.IS_PRIMARY, 1);
            operations.add(builder.build());
        }

        boolean success = false;
        // Apply all aggregation exceptions as one batch
        try {
            resolver.applyBatch(ContactsContract.AUTHORITY, operations);
            showToast(R.string.contactsJoinedMessage); //弹一个toast:Contacts linked
            success = true;
        } catch (RemoteException | OperationApplicationException e) {
            Log.e(TAG, "Failed to apply aggregation exception batch", e);
            showToast(R.string.contactSavedErrorToast);
        }

        Intent callbackIntent = intent.getParcelableExtra(EXTRA_CALLBACK_INTENT);
        if (success) {
            Uri uri = RawContacts.getContactLookupUri(resolver,
                    ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactIds[0]));
            callbackIntent.setData(uri);
        }
        deliverCallback(callbackIntent);
    }

猜你喜欢

转载自blog.csdn.net/michael_yt/article/details/78345560