注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。


这节课将会向你展示如何使用一个Intent来插入一个新的或者修改一个现有的联系人数据。与直接访问Contacts Provider不同,一个Intent会启动通讯录应用所对应的Activity。对于这节课中所描述的修改操作,Intent中将会包含启动的Activity中你所输入的那些数据。

使用Intent插入或者更新一个单一的联系人是修改Contacts Provider最好的方法,原因如下:

它能够节约你编写自己的UI和代码的时间

它可以避免修改时违反了Contacts Provider的规则而引入错误

它可以减少你需要申请的权限。你的应用不需要申请向Contacts Provider写的权限,因为它将修改操作交给了通讯录应用,而通讯录应用已经有该权限了。


一). 使用一个Intent插入一个新的联系人

你会经常希望当你的应用接收到新的数据后,允许用户插入一个新的联系人。例如,一个饭店查阅应用会允许用户在查阅时以联系人的形式添加餐馆。使用intent来做这件事,使用你知道的尽可能多的数据来创建这个intent,之后将这个intent发送到通讯录应用。

插入一个联系人时,使用通讯录应用将一个新的联系人插入到Contacts Provider的ContactsContract.RawContacts表。必要的时候,通讯录应用会在创建联系人时提示用户其账户类型和所使用的账户。当联系人已存在时,通讯录应用也会向用户发出提示。之后用户就可以选择是否放弃插入,这样的会就不会创建该联系人。更多信息可以查看Contacts Provider的API手册

创建一个Intent

首先,创建一个新的Intent对象,它具有Intents.Insert.ACTION这一action。将MIME类型设置为RawContacts.CONTENT_TYPE。例如:

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

如果你已经有了联系人的详细信息,比如一个电话号码或者email地址,你可以将它们添加到intent中作为额外的数据。对于键而言,可以使用Intents.Insert中对应的常量。联系人应用会在它的插入界面中显示这些数据,让用户进一步编辑或者添加。

/* Assumes EditText fields in your UI contain an email address
 * and a phone number.
 *
 */
private EditText mEmailAddress = (EditText) findViewById(R.id.email);
private EditText mPhoneNumber = (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(Intents.Insert.EMAIL, mEmailAddress.getText())
/*
 * In this example, sets the email type to be a work email.
 * You can set other email types as necessary.
 */
      .putExtra(Intents.Insert.EMAIL_TYPE, CommonDataKinds.Email.TYPE_WORK)
// Inserts a phone number
      .putExtra(Intents.Insert.PHONE, mPhoneNumber.getText())
/*
 * In this example, sets the phone type to be a work phone.
 * You can set other phone types as necessary.
 */
      .putExtra(Intents.Insert.PHONE_TYPE, Phone.TYPE_WORK);

一旦你创建了Intent,通过调用startActivity()来发送它。

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

这一调用会在通讯录应用中打开一个页面,允许用户添加一个新的联系人。联系人类型和名字会在顶部显示。一旦用户输入了数据并且点击了“完成”,会显示通讯录应用的联系人列表,如果用户点击“返回”则会返回到原来的应用中。


二). 使用一个Intent编辑一个已存在的联系人

如果用户已经选择了一个需要修改的联系人,使用一个Intent编辑一个已存在的联系人是很有用的。例如,一个应用发现联系人有地址但是没有邮编,那么用户就可以为他添加邮编。

要使用Intent编辑一个已经存在的联系人,使用的步骤和添加一个联系人类似。向上一节那样创建一个intent,然后对它添加联系人的Contacts.CONTENT_LOOKUP_URI和MIME类型Contacts.CONTENT_ITEM_TYPE。如果你想要用你已经有的信息编辑联系人,那么就把要修改的数据插入到intent中。注意,使用intent时,有些数据是不能修改的。这些数据可以在API文档中“Update”这一标题下找到。

最后,发送这个intent。作为响应,联系人应用会显示一个编辑页面。当用户完成编辑并保存后,联系人应用会显示一个通讯录列表。如果用户点击“返回”则会返回到原来的应用中。

创建Intent

要编辑一个联系人,调用Intent(action)来创建一个具有ACTION_EDIT这一action的intent。调用setDataAndType()来设置intent中Contacts.CONTENT_LOOKUP_URI和Contacts.CONTENT_ITEM_TYPE的值;因为调用setType()会覆盖掉当前的数据,所以你必须在同一时间设置数据和MIME类型。

要获取一个联系人的Contacts.CONTENT_LOOKUP_URI,调用Contacts.getLookupUri(id, lookupkey)方法,其中参数id是联系人的Contacts._ID的值,参数lookupkey是Contacts.LOOKUP_KEY的值。

下面的代码片段展示了如何创建这一intent:

// The Cursor that contains the Contact row
    public Cursor mCursor;
    // The index of the lookup key column in the cursor
    public int mLookupKeyIndex;
    // The index of the contact's _ID value
    public int mIdIndex;
    // The lookup key from the Cursor
    public String mCurrentLookupKey;
    // The _ID value from the Cursor
    public long mCurrentId;
    // A content URI pointing to the contact
    Uri mSelectedContactUri;
    ...
    /*
     * 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
    mLookupKeyIndex = mCursor.getColumnIndex(Contacts.LOOKUP_KEY);
    // Gets the lookup key value
    mCurrentLookupKey = mCursor.getString(mLookupKeyIndex);
    // Gets the _ID column index
    mIdIndex = mCursor.getColumnIndex(Contacts._ID);
    mCurrentId = mCursor.getLong(mIdIndex);
    mSelectedContactUri =
            Contacts.getLookupUri(mCurrentId, 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(mSelectedContactUri,Contacts.CONTENT_ITEM_TYPE);

添加导航标识

在Android 4.0(API 版本14)及后续版本中,在通讯录应用中的一个问题会导致错误地导航。当你的应用发送了一个编辑intent至通讯录应用后,用户编辑并保存了一个联系人,当他们点击返回后,会看到联系人列表。要导航到你的应用中,他们必须点击最近使用的应用清单然后再点击你的应用。

要在Android 4.0.3(API版本15)及后续版本中解决这一问题,需要再intent中添加键:“finishActivityOnSaveCompleted”,其值是:“true”。早于Android 4.0版本的系统接受这一参数,但是它不会起到任何效果。具体做法如下所示:

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

添加其他数据

要在Intent中添加其他额外的数据,调用putExtra()。你可以使用Intents.Insert中所定义的的键值来添加数据。记住ContactsContract.Contacts表中的一些列是不能修改的。这些列可以在API文档中“Update”这一标题下找到。

发送Intent

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

// Sends the Intent
    startActivity(editIntent);

三). 使用Intent让用户选择是要插入还是编辑

通过发送一个带有ACTION_INSERT_OR_EDIT这一action的intent,你可以让用户选择时要插入还是编辑一个联系人。例如:一个电子邮件客户端可以允许用户添加一个接受到的电子邮件地址到一个新的联系人中,或者将它添加到一个已存在的联系人中。将此类型intent的MIME类型设置为Contacts.CONTENT_ITEM_TYPE,但不要设置数据URI。

当你发送了这一intent,通讯录应用会显示一个联系人清单。用户既可以插入一个新的联系人,也可以选择一个现有的联系人并编辑它。任何你添加到intent中的数据会显示出来。你可以使用Intents.Insert中定义的键值。下面的代码片段展示了如何构造并发送该intent:

// 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(Contacts.CONTENT_ITEM_TYPE);
    // Add code here to insert extended data, if desired
    ...
    // Sends the Intent with an request ID
    startActivity(intentInsertEdit);