使用 Intent 修改联系人

本课介绍了如何使用 Intent 插入一位新联系人或修改某位联系人的数据。Intent 会启动相应的“通讯录”应用(该应用运行适当的 Activity),而不是直接访问联系人提供程序。对于本课中介绍的修改操作,如果您使用 Intent 发送扩展数据,则这些数据会输入到启动的 Activity 的界面。

使用 Intent 插入或更新单个联系人是修改联系人提供程序的首选方法,原因如下:

  • 您无需开发自己的界面和代码,节省了时间和精力。
  • 避免了由于不遵循联系人提供程序规则的修改而导致的错误。
  • 减少了您需要请求的权限数。您的应用无需权限即可写入联系人提供程序,因为它将修改操作委托给已具有该权限的“通讯录”应用。

使用 Intent 插入新联系人

您一般希望允许用户在您的应用收到新数据时插入新联系人。例如,一个餐厅评价应用可允许用户在评价餐厅时将其添加为联系人。要使用 Intent 进行此操作,请使用尽可能多的数据创建 Intent,然后将该 Intent 发送到“通讯录”应用。

使用“通讯录”应用插入联系人会将新的原始联系人插入到联系人提供商的 ContactsContract.RawContacts 表格中。如有必要,“通讯录”应用会在创建原始联系人时提示用户要使用的帐号类型和帐号。“通讯录”应用还会通知用户原始联系人是否已存在。如果已存在,则用户可以选择取消插入,在这种情况下,不会创建任何联系人。要详细了解原始联系人,请参阅联系人提供程序 API 指南。

创建 Intent

首先创建一个执行 Intents.Insert.ACTION 操作的新 Intent 对象。将 MIME 类型设置为 RawContacts.CONTENT_TYPE。例如:

Kotlin

    ...
    // Creates a new Intent to insert a contact
    val intent = Intent(ContactsContract.Intents.Insert.ACTION).apply {
        // Sets the MIME type to match the Contacts Provider
        type = ContactsContract.RawContacts.CONTENT_TYPE
    }
    

Java

    ...
    // Creates a new Intent to insert a contact
    Intent intent = new Intent(ContactsContract.Intents.Insert.ACTION);
    // Sets the MIME type to match the Contacts Provider
    intent.setType(ContactsContract.RawContacts.CONTENT_TYPE);
    

如果您已有该联系人的详细信息(如电话号码或电子邮件地址),则可将其作为扩展数据插入 Intent 中。对于键值对,请使用 Intents.Insert 中的适当常量。“通讯录”应用会在其插入屏幕上显示这些数据,以便用户进一步修改和添加数据。

Kotlin

    private var emailAddress: EditText? = null
    private var phoneNumber: EditText? = null
    ...
    /* Assumes EditText fields in your UI contain an email address
     * and a phone number.
     *
     */
    emailAddress = findViewById(R.id.email)
    phoneNumber = findViewById(R.id.phone)
    ...
    /*
     * Inserts new data into the Intent. This data is passed to the
     * contacts app's Insert screen
     */
    intent.apply {
        // Inserts an email address
        putExtra(ContactsContract.Intents.Insert.EMAIL, emailAddress?.text)
        /*
         * In this example, sets the email type to be a work email.
         * You can set other email types as necessary.
         */
        putExtra(
                ContactsContract.Intents.Insert.EMAIL_TYPE,
                ContactsContract.CommonDataKinds.Email.TYPE_WORK
        )
        // Inserts a phone number
        putExtra(ContactsContract.Intents.Insert.PHONE, phoneNumber?.text)
        /*
         * In this example, sets the phone type to be a work phone.
         * You can set other phone types as necessary.
         */
        putExtra(
                ContactsContract.Intents.Insert.PHONE_TYPE,
                ContactsContract.CommonDataKinds.Phone.TYPE_WORK
        )
    }
    

Java

    private EditText emailAddress = null;
    private EditText phoneNumber = null;
    ...
    /* Assumes EditText fields in your UI contain an email address
     * and a phone number.
     *
     */
    emailAddress = (EditText) findViewById(R.id.email);
    phoneNumber = (EditText) findViewById(R.id.phone);
    ...
    /*
     * Inserts new data into the Intent. This data is passed to the
     * contacts app's Insert screen
     */
    // Inserts an email address
    intent.putExtra(ContactsContract.Intents.Insert.EMAIL, emailAddress.getText())
    /*
     * In this example, sets the email type to be a work email.
     * You can set other email types as necessary.
     */
          .putExtra(ContactsContract.Intents.Insert.EMAIL_TYPE,
                ContactsContract.CommonDataKinds.Email.TYPE_WORK)
    // Inserts a phone number
          .putExtra(ContactsContract.Intents.Insert.PHONE, phoneNumber.getText())
    /*
     * In this example, sets the phone type to be a work phone.
     * You can set other phone types as necessary.
     */
          .putExtra(ContactsContract.Intents.Insert.PHONE_TYPE,
                ContactsContract.CommonDataKinds.Phone.TYPE_WORK);
    

创建 Intent 后,可通过调用 startActivity() 将其发送。

Kotlin

        /* Sends the Intent
         */
        startActivity(intent)
    

Java

        /* Sends the Intent
         */
        startActivity(intent);
    

此调用会打开“通讯录”应用中的一个屏幕,以便用户输入新的联系人。该屏幕顶部列出了联系人的帐号类型和帐号名称。用户输入数据并点击“完成”后,会看到“通讯录”应用的联系人列表。用户点击“返回”便可回到您的应用。

使用 Intent 修改已有联系人

如果用户已经选择了所需的某位已有联系人,那么使用 Intent 修改该联系人就非常有用。例如,如果应用发现联系人有邮政地址但缺少邮政编码,则可以让用户选择查询相应的邮政编码,然后将其添加到联系人中。

要使用 Intent 修改已有联系人,请使用与插入联系人类似的步骤。按照使用 Intent 插入新联系人部分所述创建 Intent,但向该 Intent 中添加 Contacts.CONTENT_LOOKUP_URI 和 MIME 类型 Contacts.CONTENT_ITEM_TYPE。如果您要使用已有的详细信息来修改该联系人,则可以将这些详细信息放入 Intent 的扩展数据中。请注意,某些名称列无法使用 Intent 进行修改;这些列在 ContactsContract.Contacts 类的 API 参考文档摘要部分以“更新”标题列出。

最后,发送该 Intent。作为响应,“通讯录”应用会显示修改屏幕。当用户完成修改并保存后,“通讯录”应用会显示联系人列表。用户点击“返回”后,会看到您的应用。

创建 Intent

要修改联系人,请调用 Intent(action) 以创建一个执行 ACTION_EDIT 操作的 Intent。调用 setDataAndType() 以将 Intent 的数据值设置为联系人的 Contacts.CONTENT_LOOKUP_URI,并将 MIME 类型设置为 Contacts.CONTENT_ITEM_TYPE MIME 类型;由于调用 setType() 会替换 Intent 的当前数据值,因此必须同时设置数据和 MIME 类型。

要获取联系人的 Contacts.CONTENT_LOOKUP_URI,请调用 Contacts.getLookupUri(id, lookupkey) 并将 Contacts._IDContacts.LOOKUP_KEY 值作为参数。

注意:联系人的 LOOKUP_KEY 值是您用于检索联系人的标识符。即使提供程序更改了联系人的行 ID 来处理内部操作,该值也保持不变。

以下代码段显示了如何创建 Intent:

Kotlin

        // The Cursor that contains the Contact row
        var mCursor: Cursor? = null
        // The index of the lookup key column in the cursor
        var lookupKeyIndex: Int = 0
        // The index of the contact's _ID value
        var idIndex: Int = 0
        // The lookup key from the Cursor
        var currentLookupKey: String? = null
        // The _ID value from the Cursor
        var currentId: Long = 0
        // A content URI pointing to the contact
        var selectedContactUri: Uri? = null
        ...
        /*
         * Once the user has selected a contact to edit,
         * this gets the contact's lookup key and _ID values from the
         * cursor and creates the necessary URI.
         */
        mCursor?.apply {
            // Gets the lookup key column index
            lookupKeyIndex = getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)
            // Gets the lookup key value
            currentLookupKey = getString(lookupKeyIndex)
            // Gets the _ID column index
            idIndex = getColumnIndex(ContactsContract.Contacts._ID)
            currentId = getLong(idIndex)
            selectedContactUri = ContactsContract.Contacts.getLookupUri(currentId, mCurrentLookupKey)
        }

        // Creates a new Intent to edit a contact
        val editIntent = Intent(Intent.ACTION_EDIT).apply {
            /*
             * Sets the contact URI to edit, and the data type that the
             * Intent must match
             */
            setDataAndType(selectedContactUri, ContactsContract.Contacts.CONTENT_ITEM_TYPE)
        }
    

Java

        // The Cursor that contains the Contact row
        public Cursor mCursor;
        // The index of the lookup key column in the cursor
        public int lookupKeyIndex;
        // The index of the contact's _ID value
        public int idIndex;
        // The lookup key from the Cursor
        public String currentLookupKey;
        // The _ID value from the Cursor
        public long currentId;
        // A content URI pointing to the contact
        Uri selectedContactUri;
        ...
        /*
         * Once the user has selected a contact to edit,
         * this gets the contact's lookup key and _ID values from the
         * cursor and creates the necessary URI.
         */
        // Gets the lookup key column index
        lookupKeyIndex = mCursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY);
        // Gets the lookup key value
        currentLookupKey = mCursor.getString(lookupKeyIndex);
        // Gets the _ID column index
        idIndex = mCursor.getColumnIndex(ContactsContract.Contacts._ID);
        currentId = mCursor.getLong(idIndex);
        selectedContactUri =
                Contacts.getLookupUri(currentId, mCurrentLookupKey);
        ...
        // Creates a new Intent to edit a contact
        Intent editIntent = new Intent(Intent.ACTION_EDIT);
        /*
         * Sets the contact URI to edit, and the data type that the
         * Intent must match
         */
        editIntent.setDataAndType(selectedContactUri, ContactsContract.Contacts.CONTENT_ITEM_TYPE);
    

添加导航标志

在 Android 4.0(API 版本 14)及更高版本中,“通讯录”应用中的一个问题会导致导航错误。如果您的应用向“通讯录”应用发送修改 Intent,并且用户修改并保存某位联系人,则当用户点击“返回”后,会看到联系人列表屏幕。要返回您的应用,用户必须点击“最近”并选择您的应用。

要在 Android 4.0.3(API 版本 15)及更高版本中解决此问题,请将扩展数据键 finishActivityOnSaveCompleted 添加到 Intent 中,并将其值设置为 true。Android 4.0 之前的 Android 版本接受此键,但没有任何作用。要设置扩展数据,请执行以下操作:

Kotlin

        // Sets the special extended data for navigation
        editIntent.putExtra("finishActivityOnSaveCompleted", true)
    

Java

        // Sets the special extended data for navigation
        editIntent.putExtra("finishActivityOnSaveCompleted", true);
    

添加其他扩展数据

要将其他扩展数据添加到 Intent,请根据需要调用 putExtra()。您可以使用 Intents.Insert 中指定的键值对为常用联系人字段添加扩展数据。请注意,ContactsContract.Contacts 表格中的某些列无法修改。这些列在 ContactsContract.Contacts 类的 API 参考摘要部分以“更新”标题列出。

发送 Intent

最后,发送您构造的 Intent。例如:

Kotlin

        // Sends the Intent
        startActivity(editIntent)
    

Java

        // Sends the Intent
        startActivity(editIntent);
    

让用户选择使用 Intent 插入或修改

您可以通过发送执行 ACTION_INSERT_OR_EDIT 操作的 Intent,使用户可以选择是插入联系人还是修改已有联系人。例如,电子邮件客户端应用可以允许用户将收到的电子邮件地址添加到新联系人,或将其添加为已有联系人的其他地址。将此 Intent 的 MIME 类型设置为 Contacts.CONTENT_ITEM_TYPE,但不要设置数据 URI。

发送此 Intent 时,“通讯录”应用会显示联系人列表。用户可以插入新联系人或选择已有联系人并进行修改。您添加到该 Intent 的扩展数据字段会填充显示的屏幕。您可以使用 Intents.Insert 中指定的任何键值对。以下代码段显示了如何构造并发送 Intent:

Kotlin

        // Creates a new Intent to insert or edit a contact
        val intentInsertEdit = Intent(Intent.ACTION_INSERT_OR_EDIT).apply {
            // Sets the MIME type
            type = ContactsContract.Contacts.CONTENT_ITEM_TYPE
        }
        // Add code here to insert extended data, if desired

        // Sends the Intent with an request ID
        startActivity(intentInsertEdit)
    

Java

        // Creates a new Intent to insert or edit a contact
        Intent intentInsertEdit = new Intent(Intent.ACTION_INSERT_OR_EDIT);
        // Sets the MIME type
        intentInsertEdit.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
        // Add code here to insert extended data, if desired
        ...
        // Sends the Intent with an request ID
        startActivity(intentInsertEdit);