使用意图修改联系人

本课将向您展示如何使用 Intent 插入新联系人或修改联系人的数据。不是直接访问 Contacts Provider,Intent 会启动联系人应用,该应用会运行相应的 Activity。对于本课中描述的修改操作,如果您在 Intent 中发送扩展数据,这些数据将被输入到启动的 Activity 的 UI 中。

由于以下原因,使用 Intent 插入或更新单个联系人是修改 Contacts Provider 的首选方法

  • 它节省了您开发自己的 UI 和代码的时间和精力。
  • 它可以避免由于不遵循 Contacts Provider 规则的修改而导致的错误。
  • 它减少了您需要请求的权限数量。您的应用不需要写入 Contacts Provider 的权限,因为它将修改委托给联系人应用,该应用已经拥有该权限。

使用意图插入新联系人

当您的应用收到新数据时,您通常希望允许用户插入新联系人。例如,餐厅评论应用可以允许用户在评论餐厅时将其添加为联系人。要使用意图执行此操作,请使用尽可能多的可用数据创建意图,然后将意图发送到联系人应用。

使用联系人应用插入联系人会将新的原始联系人插入到 Contacts Provider 的 ContactsContract.RawContacts 表中。如有必要,联系人应用会提示用户在创建原始联系人时使用帐户类型和帐户。联系人应用还会通知用户原始联系人是否已存在。然后,用户可以选择取消插入,在这种情况下不会创建联系人。要详细了解原始联系人,请参阅 Contacts Provider API 指南。

创建意图

首先,使用操作 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);

如果您已经拥有联系人的详细信息,例如电话号码或电子邮件地址,则可以将它们作为扩展数据插入到意图中。对于键值,请使用 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 编辑现有联系人很有用。例如,一个查找拥有邮政地址但缺少邮政编码的联系人的应用可以为用户提供查找邮政编码并将其添加到联系人的选项。

要使用意图编辑现有联系人,请使用类似于插入联系人的过程。按照使用意图插入新联系人一节中所述创建意图,但将联系人的Contacts.CONTENT_LOOKUP_URI和MIME类型Contacts.CONTENT_ITEM_TYPE添加到意图中。如果您想使用已有的详细信息编辑联系人,可以将它们放在意图的扩展数据中。请注意,某些名称列无法使用意图进行编辑;这些列列在ContactsContract.Contacts类的 API 参考的摘要部分的“更新”标题下。

最后,发送意图。作为响应,联系人应用程序将显示一个编辑屏幕。当用户完成编辑并保存编辑后,联系人应用程序将显示一个联系人列表。当用户单击返回时,将显示您的应用程序。

创建意图

要编辑联系人,请调用Intent(action)以使用操作ACTION_EDIT创建意图。调用setDataAndType()以将意图的数据值设置为联系人的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 以处理内部操作。

以下代码段显示了如何创建意图

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)及更高版本中,联系人应用程序中的一个问题会导致导航错误。当您的应用程序向联系人应用程序发送编辑意图时,用户编辑并保存联系人后,当他们单击返回时,他们会看到联系人列表屏幕。要返回到您的应用程序,他们必须单击最近并选择您的应用程序。

要解决 Android 4.0.3(API 级别 15)及更高版本中的此问题,请将扩展数据键finishActivityOnSaveCompleted添加到意图中,其值为true。Android 4.0 之前的版本接受此键,但它没有效果。要设置扩展数据,请执行以下操作

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 参考的摘要部分的“更新”标题下。

发送意图

最后,发送您构建的意图。例如

Kotlin

    // Sends the Intent
    startActivity(editIntent)

Java

    // Sends the Intent
    startActivity(editIntent);

允许用户选择使用意图插入或编辑

您可以允许用户选择插入联系人还是编辑现有联系人,方法是发送一个操作为ACTION_INSERT_OR_EDITIntent。例如,电子邮件客户端应用程序可以允许用户将传入的电子邮件地址添加到新联系人,或将其添加为现有联系人的附加地址。将此意图的 MIME 类型设置为Contacts.CONTENT_ITEM_TYPE,但不要设置数据 URI。

当您发送此意图时,联系人应用程序将显示一个联系人列表。用户可以插入新联系人,也可以选择现有联系人并进行编辑。您添加到意图中的任何扩展数据字段都会填充出现的屏幕。您可以使用Intents.Insert中指定的任何键值。以下代码段显示了如何构建和发送意图

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);