> 编写:[spencer198711](https://github.com/spencer198711) - 原文:[http://developer.android.com/training/contacts-provider/modify-data.html](http://developer.android.com/training/contacts-provider/modify-data.html)
这一课介绍如何使用[Intent](http://developer.android.com/reference/android/content/Intent.html)去插入一个新的联系人或者修改联系人的数据。我们不是直接访问Contacts Provider,而是通过Intent启动Contacts应用去运行适当的[Activity](# "An activity represents a single screen with a user interface.")。对于这一课中描述的数据修改行为,如果你向Intent发送扩展的数据,它会自动填充进启动的[Activity](# "An activity represents a single screen with a user interface.")页面中。
使用Intent去插入或者更新一个联系人是比较推荐的修改Contacts Provider的做法。原因如下:
- 节省了我们自行开发UI和编写代码的时间和精力。
- 避免了由于不按照Contacts Provider的规则去修改而产生的错误。
- 减少应用需要申请的权限数量。因为我们的应用把修改行为委托给已经拥有写Contacts Provider权限的Contacts应用,所以我们的应用不需要再去申请这个权限,。
### 使用Intent插入新的联系人
当我们的应用接收到新的数据时,我们通常会允许用户去插入一个新的联系人。例如,一个餐馆评论应用可以允许用户在评论餐馆的时候,把这个餐馆添加为一个联系人。可以使用Intent去做这个任务,使用我们拥有的尽可能多的数据去创建对应的Intent,然后发送这个Intent到Contacts应用。
使用Contacts应用去插入一个联系人将会向Contacts Provider中的[ContactsContract.RawContacts](http://developer.android.com/reference/android/provider/ContactsContract.RawContacts.html)表中插入一个原始联系人。必要的情况下,在创建原始联系人的时候,Contacts应用将会提示用户选择账户类型和要使用的账户。如果联系人已经存在,Contacts应用也会告知用户。用户将会有取消插入的选项,在这种情况下不会有联系人被创建。想要知道更多关于原始联系人的信息,请参阅[Contacts Provider](http://developer.android.com/guide/topics/providers/contacts-provider.html)的API指导。
### 创建一个Intent
利用Intents.Insert.ACTION创建一个新的Intent对象,并设置其MIME类型为[RawContacts.CONTENT_TYPE](http://developer.android.com/reference/android/provider/ContactsContract.RawContacts.html#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](http://developer.android.com/reference/android/provider/ContactsContract.Intents.Insert.html)中对应的常量。Contacts应用将会在插入界面显示这些数据,以便用户作进一步的数据编辑和数据添加。
~~~
/* 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()将其发送到Contacts应用。
~~~
/* Sends the Intent
*/
startActivity(intent);
~~~
这个调用将会打开Contacts应用的界面,并允许用户进入一个新的联系人。这个联系人的账户类型和账户名字列在屏幕的上方。一旦用户输入数据并点击_确定_,Contacts应用的联系人列表则会显示出来。用户可以点击_Back_键返回到我们自己创建的应用。
### 使用Intent编辑已经存在的联系人
如果用户已经选择了一个感兴趣的联系人,使用Intent去编辑这个已存在的联系人会很有用。例如,一个用来查找拥有邮政地址但是缺少邮政编码的联系人的应用,可以给用户提供查找邮政编码的选项,然后把找到的邮政编码添加到这个联系人中。
使用Intent编辑已经存在的联系人,同插入一个联系人的步骤类似。像前面介绍的[使用Intent插入新的联系人]()创建一个Intent,但是需要给这个Intent添加对应联系人的[Contacts.CONTENT_LOOKUP_URI](http://developer.android.com/reference/android/provider/ContactsContract.Contacts.html#CONTENT_LOOKUP_URI)和MIME类型[Contacts.CONTENT_ITEM_TYPE](http://developer.android.com/reference/android/provider/ContactsContract.Contacts.html#CONTENT_ITEM_TYPE)。如果想要使用已经拥有的详情信息编辑这个联系人,我们需要把这些数据放到Intent的扩展数据中。同时注意有些列是不能使用Intent编辑的,这些不可编辑的列在[ContactsContract.Contacts](http://developer.android.com/reference/android/provider/ContactsContract.Contacts.html) 摘要部分“Update”标题下有列出。
最后,发送这个Intent。Contacts应用会显示一个编辑界面作为回应。当用户编辑完成并保存,Contacts应用会显示一个联系人列表。当用户点击_Back_,我们自己的应用会出现。
### 创建Intent
为了能够编辑一个联系人,需要调用Intent(action)去创建一个拥有ACTION_EDIT行为的Intent。调用setDataAndType()去设置这个Intent要编辑的联系人的Contacts.CONTENT_LOOKUP_URI和MIME类型Contacts.CONTENT_ITEM_TYPE。因为调用setType()会重写Intent当前的数据,所以我们必须同时设置数据和MIME类型。
为了得到联系人的Contacts.CONTENT_LOOKUP_URI,需要调用Contacts.getLookupUri(id, lookupkey)方法,该方法的参数分别是联系人的Contacts._ID和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)和更高的版本,Contacts应用中的一个问题会导致错误的页面导航。我们的应用发送一个编辑联系人的Intent到Contacts应用,用户编辑并保存这个联系人,当用户点击_Back_键的时候会看到联系人列表页面。用户需要点击最近使用的应用,然后选择我们的应用,才能返回到我们自己的应用。
要在Android 4.0.3(API版本15)及以后的版本解决此问题,需要添加`finishActivityOnSaveCompleted`扩展数据参数到这个Intent,并将它的值设置为true。Android 4.0之前的版本也能够接受这个参数,但是不起作用。为了设置扩展数据,请按照以下方式去做:
~~~
// Sets the special extended data for navigation
editIntent.putExtra("finishActivityOnSaveCompleted", true);
~~~
### 添加其他的扩展数据
对Intent添加额外的扩展数据,需要调用putExtra()。可以为常见的联系人数据字段添加扩展数据,这些常见字段的key值可以从[Intents.Insert](http://developer.android.com/reference/android/provider/ContactsContract.Intents.Insert.html) API参考文档中查到。记住ContactsContract.Contacts表中有些列是不能编辑的,这些列在[ContactsContract.Contacts](http://developer.android.com/reference/android/provider/ContactsContract.Contacts.html)的摘要部分“Update”标题下有列出。
### 发送Intent
最后,发送我们已经构建好的Intent。例如:
~~~
// Sends the Intent
startActivity(editIntent);
~~~
### 使用Intent让用户去选择是插入还是编辑联系人
我们可以通过发送带有`ACTION_INSERT_OR_EDIT`行为的Intent,让用户去选择是插入联系人还是编辑已有的联系人。例如,一个email客户端应用会允许用户添加一个收件地址到新的联系人,或者仅仅作为额外的邮件地址添加到已有的联系人。需要为这个Intent设置MIME类型Contacts.CONTENT_ITEM_TYPE,但是不需要设置数据URI。
当我们发送这个Intent后,Contacts应用会展示一个联系人列表。用户可以选择是插入一个新的联系人还是挑选一个存在的联系人去编辑。任何添加到Intent中的扩展数据字段都会填充在界面上。我们可以使用任何在[Intents.Insert](http://developer.android.com/reference/android/provider/ContactsContract.Intents.Insert.html)中指定的的key值。以下的代码片段展示了如何构建和发送这个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);
~~~
- 序言
- Android入门基础:从这里开始
- 建立第一个App
- 创建Android项目
- 执行Android程序
- 建立简单的用户界面
- 启动其他的Activity
- 添加ActionBar
- 建立ActionBar
- 添加Action按钮
- 自定义ActionBar的风格
- ActionBar的覆盖层叠
- 兼容不同的设备
- 适配不同的语言
- 适配不同的屏幕
- 适配不同的系统版本
- 管理Activity的生命周期
- 启动与销毁Activity
- 暂停与恢复Activity
- 停止与重启Activity
- 重新创建Activity
- 使用Fragment建立动态的UI
- 创建一个Fragment
- 建立灵活动态的UI
- Fragments之间的交互
- 数据保存
- 保存到Preference
- 保存到文件
- 保存到数据库
- 与其他应用的交互
- Intent的发送
- 接收Activity返回的结果
- Intent过滤
- Android分享操作
- 分享简单的数据
- 给其他App发送简单的数据
- 接收从其他App返回的数据
- 给ActionBar增加分享功能
- 分享文件
- 建立文件分享
- 分享文件
- 请求分享一个文件
- 获取文件信息
- 使用NFC分享文件
- 发送文件给其他设备
- 接收其他设备的文件
- Android多媒体
- 管理音频播放
- 控制音量与音频播放
- 管理音频焦点
- 兼容音频输出设备
- 拍照
- 简单的拍照
- 简单的录像
- 控制相机硬件
- 打印
- 打印照片
- 打印HTML文档
- 打印自定义文档
- Android图像与动画
- 高效显示Bitmap
- 高效加载大图
- 非UI线程处理Bitmap
- 缓存Bitmap
- 管理Bitmap的内存
- 在UI上显示Bitmap
- 使用OpenGL ES显示图像
- 建立OpenGL ES的环境
- 定义Shapes
- 绘制Shapes
- 运用投影与相机视图
- 添加移动
- 响应触摸事件
- 添加动画
- View间渐变
- 使用ViewPager实现屏幕侧滑
- 展示卡片翻转动画
- 缩放View
- 布局变更动画
- Android网络连接与云服务
- 无线连接设备
- 使得网络服务可发现
- 使用WiFi建立P2P连接
- 使用WiFi P2P服务
- 执行网络操作
- 连接到网络
- 管理网络
- 解析XML数据
- 高效下载
- 为网络访问更加高效而优化下载
- 最小化更新操作的影响
- 避免下载多余的数据
- 根据网络类型改变下载模式
- 云同步
- 使用备份API
- 使用Google Cloud Messaging
- 解决云同步的保存冲突
- 使用Sync Adapter传输数据
- 创建Stub授权器
- 创建Stub Content Provider
- 创建Sync Adpater
- 执行Sync Adpater
- 使用Volley执行网络数据传输
- 发送简单的网络请求
- 建立请求队列
- 创建标准的网络请求
- 实现自定义的网络请求
- Android联系人与位置信息
- Android联系人信息
- 获取联系人列表
- 获取联系人详情
- 使用Intents修改联系人信息
- 显示联系人头像
- Android位置信息
- 获取最后可知位置
- 获取位置更新
- 显示位置地址
- 创建和监视地理围栏
- Android可穿戴应用
- 赋予Notification可穿戴特性
- 创建Notification
- 在Notifcation中接收语音输入
- 为Notification添加显示页面
- 以Stack的方式显示Notifications
- 创建可穿戴的应用
- 创建并运行可穿戴应用
- 创建自定义的布局
- 添加语音功能
- 打包可穿戴应用
- 通过蓝牙进行调试
- 创建自定义的UI
- 定义Layouts
- 创建Cards
- 创建Lists
- 创建2D-Picker
- 创建确认界面
- 退出全屏的Activity
- 发送并同步数据
- 访问可穿戴数据层
- 同步数据单元
- 传输资源
- 发送与接收消息
- 处理数据层的事件
- Android TV应用
- 创建TV应用
- 创建TV应用的第一步
- 处理TV硬件部分
- 创建TV的布局文件
- 创建TV的导航栏
- 创建TV播放应用
- 创建目录浏览器
- 提供一个Card视图
- 创建详情页
- 显示正在播放卡片
- 帮助用户在TV上探索内容
- TV上的推荐内容
- 使得TV App能够被搜索
- 使用TV应用进行搜索
- 创建TV游戏应用
- 创建TV直播应用
- TV Apps Checklist
- Android企业级应用
- Ensuring Compatibility with Managed Profiles
- Implementing App Restrictions
- Building a Work Policy Controller
- Android交互设计
- 设计高效的导航
- 规划屏幕界面与他们之间的关系
- 为多种大小的屏幕进行规划
- 提供向下和横向导航
- 提供向上和历史导航
- 综合:设计样例 App
- 实现高效的导航
- 使用Tabs创建Swipe视图
- 创建抽屉导航
- 提供向上的导航
- 提供向后的导航
- 实现向下的导航
- 通知提示用户
- 建立Notification
- 当启动Activity时保留导航
- 更新Notification
- 使用BigView风格
- 显示Notification进度
- 增加搜索功能
- 建立搜索界面
- 保存并搜索数据
- 保持向下兼容
- 使得你的App内容可被Google搜索
- 为App内容开启深度链接
- 为索引指定App内容
- Android界面设计
- 为多屏幕设计
- 兼容不同的屏幕大小
- 兼容不同的屏幕密度
- 实现可适应的UI
- 创建自定义View
- 创建自定义的View类
- 实现自定义View的绘制
- 使得View可交互
- 优化自定义View
- 创建向后兼容的UI
- 抽象新的APIs
- 代理至新的APIs
- 使用旧的APIs实现新API的效果
- 使用版本敏感的组件
- 实现辅助功能
- 开发辅助程序
- 开发辅助服务
- 管理系统UI
- 淡化系统Bar
- 隐藏系统Bar
- 隐藏导航Bar
- 全屏沉浸式应用
- 响应UI可见性的变化
- 创建使用Material Design的应用
- 开始使用Material Design
- 使用Material的主题
- 创建Lists与Cards
- 定义Shadows与Clipping视图
- 使用Drawables
- 自定义动画
- 维护兼容性
- Android用户输入
- 使用触摸手势
- 检测常用的手势
- 跟踪手势移动
- Scroll手势动画
- 处理多触摸手势
- 拖拽与缩放
- 管理ViewGroup中的触摸事件
- 处理键盘输入
- 指定输入法类型
- 处理输入法可见性
- 兼容键盘导航
- 处理按键动作
- 兼容游戏控制器
- 处理控制器输入动作
- 支持不同的Android系统版本
- 支持多个控制器
- Android后台任务
- 在IntentService中执行后台任务
- 创建IntentService
- 发送工作任务到IntentService
- 报告后台任务执行状态
- 使用CursorLoader在后台加载数据
- 使用CursorLoader执行查询任务
- 处理查询的结果
- 管理设备的唤醒状态
- 保持设备的唤醒
- 制定重复定时的任务
- Android性能优化
- 管理应用的内存
- 代码性能优化建议
- 提升Layout的性能
- 优化layout的层级
- 使用include标签重用layouts
- 按需加载视图
- 使得ListView滑动顺畅
- 优化电池寿命
- 监测电量与充电状态
- 判断与监测Docking状态
- 判断与监测网络连接状态
- 根据需要操作Broadcast接受者
- 多线程操作
- 在一个线程中执行一段特定的代码
- 为多线程创建线程池
- 启动与停止线程池中的线程
- 与UI线程通信
- 避免出现程序无响应ANR
- JNI使用指南
- 优化多核处理器(SMP)下的Android程序
- Android安全与隐私
- Security Tips
- 使用HTTPS与SSL
- 为防止SSL漏洞而更新Security
- 使用设备管理条例增强安全性
- Android测试程序
- 测试你的Activity
- 建立测试环境
- 创建与执行测试用例
- 测试UI组件
- 创建单元测试
- 创建功能测试
- 術語表