代码之家  ›  专栏  ›  技术社区  ›  Android Developer

创建新联系人而不是更新现有联系人

  •  2
  • Android Developer  · 技术社区  · 6 年前

    我正在将我的应用程序与android默认联系人应用程序集成。我想在每个联系人详细信息中显示一个选项“xyz使用我的应用程序”。我可以在帐户部分看到我的应用程序,其中包含一个同步联系人的选项,但我的应用程序仍然没有与现有联系人合并,而是创建一个新联系人并在其中合并。

    performSync()方法

    private static void addContact(ContentResolver contentResolver,int name, int phoneNumber) {
        Log.i("XYZ", "Adding contact: " + name);
        ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
    
        //Create our RawContact
        ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI);
        builder.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, name);
        builder.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, "com.example.xyz.myapplication");
        builder.withValue(ContactsContract.RawContacts.SYNC1, phoneNumber);
        operationList.add(builder.build());
    
        //Create a Data record of common type 'StructuredName' for our RawContact
        builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
        builder.withValueBackReference(ContactsContract.CommonDataKinds.StructuredName.RAW_CONTACT_ID, 0);
        builder.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
        builder.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);
        operationList.add(builder.build());
    
        //Create a Data record of custom type "vnd.android.cursor.item/vnd.com.example.xyz.myapplication.profile" to display a link to the Last.fm profile
        builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
        builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0);
        builder.withValue(ContactsContract.Data.MIMETYPE, "vnd.android.cursor.item/vnd.com.example.xyz.myapplication.profile");
        builder.withValue(ContactsContract.Data.DATA1, phoneNumber);
        builder.withValue(ContactsContract.Data.DATA2, "Last.fm Profile");
        builder.withValue(ContactsContract.Data.DATA3, "View profile");
        operationList.add(builder.build());
    
        try {
            contentResolver.applyBatch(ContactsContract.AUTHORITY, operationList);
        } catch (Exception e) {
            Log.e("XYZ", "Something went wrong during creation! " + e);
            e.printStackTrace();
        }
    }
    
    2 回复  |  直到 6 年前
        1
  •  3
  •   marmor    6 年前

    在你的 addContact 你缺少的代码告诉我们 Contacts DB 将新的原始联系人加入到现有联系人中,以便该联系人现在将包含您的原始联系人,并且在“联系人”应用程序中打开该联系人时,将显示应用程序特定的行。

    检查这个关于如何加入一个团队的答案 RawContact 到现有联系人中: why won't contacts aggregate?

    你可能需要通过一些 RawContact ID

    而不是将聚合操作与 原始联系人 插入操作,让我们试着分成两部分 applyBatch 电话,还有,让我们把你和 全部 请尝试以下代码,确保将现有的 联系人id 您的新原始联系人id .

    private void joinIntoExistingContact(long existingContactId, long newRawContactId) {
    
        // get all existing raw-contact-ids that belong to the contact-id
        List<Long> existingRawIds = new ArrayList<>();
        Cursor cur = getContentResolver().query(RawContacts.CONTENT_URI, new String[] { RawContacts._ID }, RawContacts.CONTACT_ID + "=" + existingContactId, null, null);
        while (cur.moveToNext()) {
            existingRawIds.add(cur.getLong(0));
        }
        cur.close();
        Log.i("Join", "Found " + existingRawIds.size() + " raw-contact-ids");
    
        List<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
    
        // go over all existing raw ids, and join with our new one
        for (Long existingRawId : existingRawIds) {
            Builder builder = ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI);
            builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER);
            builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, newRawContactId);
            builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, existingRawId);
            ops.add(builder.build());
        }
    
        contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
    }
    


    duplicate questions ,一个就够了。

    另一个更新

    Data 原始联系人 ID,和 Contact 身份证。

    CommonDataKinds.Phone._ID 数据 ID,标识数据表中存储电话号码的特定行。

    你可以从 Phone 也可以将其他ID放入表中,使用: CommonDataKinds.Phone.RAW_CONTACT_ID CommonDataKinds.Phone.CONTACT_ID

    您可以在此处阅读更多内容: https://stackoverflow.com/a/50084029/819355

        2
  •  1
  •   AskNilesh    6 年前

    试试这个,这是我的工作代码

    主要活动

    public class MainActivity extends AppCompatActivity {
    
        private ArrayList<String> mNames = new ArrayList<>();
        private ArrayList<String> mIDs = new ArrayList<>();
        private ArrayList<String> mNumbers = new ArrayList<>();
    
        @SuppressLint("StaticFieldLeak")
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED &&
                    ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
                            != PackageManager.PERMISSION_GRANTED) {
    
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 123);
    
            } else {
    
    
    //      Retrieve names from phone's contact list and save in mNames
                getContactDataBefore();
    
    //      Apply changes to phone's contact list
                new AsyncTask<String, String, String>() {
    
                    @Override
                    protected String doInBackground(String... params) {
                        String name, number, id;
                        for (int i = 0; i < mIDs.size(); i++) {
    //                    name = mNames.get(i);
                            id = mIDs.get(i);
                            number = mNumbers.get(i);
                            ContactsManager.addContact(MainActivity.this, new MyContact(id, number));
                        }
                        return null;
                    }
    
                    @Override
                    protected void onPostExecute(String s) {
                        getContactDataAfter();
                    }
                }.execute();
            }
    
        }
    
        private void getContactDataBefore() {
            int i = 0;
    
            // query all contact id's from device
            Cursor c1 = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
                    new String[]{ContactsContract.Contacts._ID}, null, null, null);
    
            if ((c1 != null) && c1.moveToFirst()) {
    
    
                do {
                    mIDs.add(c1.getString(c1.getColumnIndexOrThrow(ContactsContract.Contacts._ID)));
    
                    i++;
                } while (c1.moveToNext() && i < c1.getCount());
    
                c1.close();
    
            }
    
            getPhoneNumber();
        }
    
        private void getPhoneNumber(){
    
    
            for (String data:mIDs){
    
                Cursor cursor = getContentResolver().query(
                        ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                        null,
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
                        new String[]{data}, null);
    
                while (cursor.moveToNext())
                {
                    mNumbers.add(cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
                }
    
                cursor.close();
            }
    
        }
        /**
         * Method to fetch contacts after updation (for logging purposes)
         */
        private void getContactDataAfter() {
            Cursor c = getContentResolver()
                    .query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
    
            List<String> RIds = new ArrayList<>();
            mIDs = new ArrayList<>();
            mNumbers = new ArrayList<>();
            int i = 0;
    
            if (c != null && c.moveToFirst()) {
                do {
                    mIDs.add(c.getString(c
                            .getColumnIndexOrThrow(ContactsContract.Contacts._ID)));
                    mNames.add(c.getString(c
                            .getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME)));
    
                    Cursor c2 = getContentResolver()
                            .query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                                    new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER},
                                    ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?",
                                    new String[]{mIDs.get(i)}, null);
    
                    if (c2 != null && c2.moveToFirst()) {
                        do {
                            mNumbers.add(c2.getString(c2
                                    .getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER)));
                        } while (c2.moveToNext());
                        c2.close();
                    }
    
                    Cursor rawcontacts = getContentResolver()
                            .query(ContactsContract.RawContacts.CONTENT_URI,
                                    new String[]{ContactsContract.RawContacts._ID},
                                    ContactsContract.RawContacts.CONTACT_ID + "=?",
                                    new String[]{mIDs.get(i)}, null);
    
                    if (rawcontacts != null && rawcontacts.moveToFirst()) {
                        do {
                            RIds.add(rawcontacts.getString(rawcontacts
                                    .getColumnIndexOrThrow(ContactsContract.RawContacts._ID)));
                        } while (rawcontacts.moveToNext());
                        rawcontacts.close();
                    }
    
                    i++;
                } while (c.moveToNext());
                c.close();
            }
        }
    }
    

    验证器活动

    public class AuthenticatorActivity extends AccountAuthenticatorActivity {
    
        private AccountManager mAccountManager;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_authenticator);
    
    
            Intent res = new Intent();
            res.putExtra(AccountManager.KEY_ACCOUNT_NAME, Constants.ACCOUNT_NAME);
            res.putExtra(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE);
            res.putExtra(AccountManager.KEY_AUTHTOKEN, Constants.ACCOUNT_TOKEN);
            Account account = new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE);
            mAccountManager = AccountManager.get(this);
            mAccountManager.addAccountExplicitly(account, null, null);
    //      mAccountManager.setAuthToken(account, Constants.AUTHTOKEN_TYPE_FULL_ACCESS, Constants.ACCOUNT_TOKEN);
            ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true);
            setAccountAuthenticatorResult(res.getExtras());
            setResult(RESULT_OK, res);
            finish();
        }
    }
    

    同步适配器

    public class SyncAdapter extends AbstractThreadedSyncAdapter {
    
        private Context mContext;
    
        public SyncAdapter(Context context, boolean autoInitialize) {
            super(context, autoInitialize);
            mContext = context;
        }
    
        @Override
        public void onPerformSync(Account account, Bundle extras, String authority,
                                  ContentProviderClient provider, SyncResult syncResult) {
        }
    }
    

    同步服务

    public class SyncService extends Service {
    
        private static final Object sSyncAdapterLock = new Object();
        private static SyncAdapter mSyncAdapter = null;
    
        @Override
        public void onCreate() {
            synchronized (sSyncAdapterLock){
                if(mSyncAdapter == null){
                    mSyncAdapter = new SyncAdapter(getApplicationContext(),true);
                }
            }
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return mSyncAdapter.getSyncAdapterBinder();
        }
    }
    

    身份验证服务

    public class AuthenticationService extends Service {
    
        private static final String TAG = "AuthenticationService";
        private Authenticator mAuthenticator;
    
        @Override
        public void onCreate() {
            if (android.util.Log.isLoggable(TAG, android.util.Log.VERBOSE)) {
                android.util.Log.v(TAG, "SyncAdapter Authentication Service started.");
            }
            mAuthenticator = new Authenticator(this);
        }
    
        @Override
        public void onDestroy() {
            if (android.util.Log.isLoggable(TAG, android.util.Log.VERBOSE)) {
                Log.v(TAG, "SyncAdapter Authentication Service stopped.");
            }
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "getBinder()...  returning the AccountAuthenticator binder for intent "
                        + intent);
            }
            return mAuthenticator.getIBinder();
        }
    }
    

    验证器

    public class Authenticator extends AbstractAccountAuthenticator {
    
        private final Context mContext;
    
        public Authenticator(Context context) {
            super(context);
            mContext = context;
        }
    
        @Override
        public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
            return null;
        }
    
        @Override
        public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
            final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
            intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
    
            final Bundle bundle = new Bundle();
            bundle.putParcelable(AccountManager.KEY_INTENT, intent);
            return bundle;
        }
    
        @Override
        public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
            return null;
        }
    
        @Override
        public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
            final Bundle result = new Bundle();
            result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
            result.putString(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE);
            return result;
        }
    
        @Override
        public String getAuthTokenLabel(String authTokenType) {
            return null;
        }
    
        @Override
        public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
            return null;
        }
    
        @Override
        public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
            return null;
        }
    }
    

    常量

    public class Constants {
    
        public static final String ACCOUNT_TYPE = "com.example.ajay.contacts_4";
        public static final String ACCOUNT_NAME = "Nilesh_Rathod";
        public static final String ACCOUNT_TOKEN = "733N";
    }
    

    联系人管理员

    public class ContactsManager {
    
        private static String MIMETYPE = "vnd.android.cursor.item/com.example.ajay.contacts_4";
    
    
        public static void addContact(Context context, MyContact contact) {
            ContentResolver resolver = context.getContentResolver();
            boolean mHasAccount = isAlreadyRegistered(resolver, contact.Id);
    
            if (mHasAccount) {
                Log.I("Account is Exist");
            } else {
    
                ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
    
                // insert account name and account type
                ops.add(ContentProviderOperation
                        .newInsert(addCallerIsSyncAdapterParameter(ContactsContract.RawContacts.CONTENT_URI, true))
                        .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, Constants.ACCOUNT_NAME)
                        .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, Constants.ACCOUNT_TYPE)
                        .withValue(ContactsContract.RawContacts.AGGREGATION_MODE,
                                ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT)
                        .build());
    
                // insert contact number
                ops.add(ContentProviderOperation
                        .newInsert(addCallerIsSyncAdapterParameter(ContactsContract.Data.CONTENT_URI, true))
                        .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                        .withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                        .withValue(CommonDataKinds.Phone.NUMBER, contact.number)
                        .build());
    
    
                // insert mime-type data
                ops.add(ContentProviderOperation
                        .newInsert(addCallerIsSyncAdapterParameter(ContactsContract.Data.CONTENT_URI, true))
                        .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                        .withValue(ContactsContract.Data.MIMETYPE, MIMETYPE)
                        .withValue(ContactsContract.Data.DATA1, 12345)
                        .withValue(ContactsContract.Data.DATA2, "Nilesh")
                        .withValue(ContactsContract.Data.DATA3, "ContactsDemo")
                        .build());
    
    
            }
        }
    
        /**
         * Check if contact is already registered with app
         */
        public static boolean isAlreadyRegistered(ContentResolver resolver, String id) {
    
            boolean isRegistered = false;
            List<String> str = new ArrayList<>();
    
            //query raw contact id's from the contact id
            Cursor c = resolver.query(RawContacts.CONTENT_URI, new String[]{RawContacts._ID},
                    RawContacts.CONTACT_ID + "=?",
                    new String[]{id}, null);
    
            //fetch all raw contact id's and save them in a list of string
            if (c != null && c.moveToFirst()) {
                do {
                    str.add(c.getString(c.getColumnIndexOrThrow(RawContacts._ID)));
                } while (c.moveToNext());
                c.close();
            }
    
            //query account types and check the account type for each raw contact id
            for (int i = 0; i < str.size(); i++) {
                Cursor c1 = resolver.query(RawContacts.CONTENT_URI, new String[]{RawContacts.ACCOUNT_TYPE},
                        RawContacts._ID + "=?",
                        new String[]{str.get(i)}, null);
    
                if (c1 != null) {
                    c1.moveToFirst();
                    String accType = c1.getString(c1.getColumnIndexOrThrow(RawContacts.ACCOUNT_TYPE));
                    if (accType != null && accType.equals("com.example.ajay.contacts_4")) {
                        isRegistered = true;
                        break;
                    }
                    c1.close();
                }
            }
    
            return isRegistered;
        }
    
        /**
         * Check for sync call
         */
        private static Uri addCallerIsSyncAdapterParameter(Uri uri, boolean isSyncOperation) {
            if (isSyncOperation) {
                return uri.buildUpon()
                        .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
                        .build();
            }
            return uri;
        }
    
    
    }
    

    验证器.xml

    <?xml version="1.0" encoding="utf-8"?>
    <account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
        android:accountType="com.example.ajay.contacts_4"
        android:icon="@drawable/icon"
        android:smallIcon="@drawable/icon"
        android:label="@string/app_name" />
    

    联系人.xml

    <?xml version="1.0" encoding="utf-8"?>
    <ContactsSource
        xmlns:android="http://schemas.android.com/apk/res/android">
        <ContactsDataKind
            android:mimeType="vnd.android.cursor.item/com.example.ajay.contacts_4"
            android:icon="@drawable/icon"
            android:summaryColumn="data2"
            android:detailColumn="data3" />
    </ContactsSource>
    

    syncadapter.xml文件

    <?xml version="1.0" encoding="utf-8"?>
    <sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
        android:contentAuthority="com.android.contacts"
        android:accountType="com.example.ajay.contacts_4"
        android:supportsUploading="false"
        android:userVisible="true" />
    

    显示

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        package="neel.com.contactssyncingapp">
    
        <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
        <uses-permission android:name="android.permission.WRITE_CONTACTS" />
        <uses-permission android:name="android.permission.READ_CONTACTS" />
        <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
        <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
        <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
        <uses-permission android:name="android.permission.INTERNET" />
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
    
            <service android:name=".utils.AuthenticationService" >
                <intent-filter>
                    <action android:name="android.accounts.AccountAuthenticator" />
                </intent-filter>
    
                <meta-data
                    android:name="android.accounts.AccountAuthenticator"
                    android:resource="@xml/authenticator" />
            </service>
    
            <service android:name=".sync.SyncService" >
                <intent-filter>
                    <action android:name="android.content.SyncAdapter" />
                </intent-filter>
    
                <meta-data
                    android:name="android.content.SyncAdapter"
                    android:resource="@xml/syncadapter" />
                <meta-data
                    android:name="android.provider.CONTACTS_STRUCTURE"
                    android:resource="@xml/contacts" />
            </service>
    
            <activity android:name=".activity.MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
    
                </intent-filter>
            </activity>
    
    
            <activity
                android:name=".activity.ContactActivity"
                android:label="ContactActivity"
                android:screenOrientation="portrait"
                android:exported="true">
                <intent-filter>
                    <action android:name="android.intent.action.VIEW" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <data android:mimeType="vnd.android.cursor.item/com.example.ajay.contacts_4" />
                </intent-filter>
            </activity>
    
    
            <activity android:name=".activity.AuthenticatorActivity" />
        </application>
    
    </manifest>
    

    输出

    enter image description here

    public class ContactActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_contact);
    
    
            Uri intentData = getIntent().getData();
            if (!Uri.EMPTY.equals(intentData))
            {
                Cursor cursor = getContentResolver().query(intentData, null, null, null, null);
                if (cursor.moveToNext())
                {
                    String username = cursor.getString(cursor.getColumnIndex("data2"));
                    String number = cursor.getString(cursor.getColumnIndex("data3"));
    
                    Log.e("USER_NAME",username);
                    Log.e("USER_NUMBER",number);
                }
            }
        }
    }