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

原文链接:http://developer.android.com/training/contacts-provider/retrieve-details.html


这节课将会展示如何获取一个联系人的详细数据,比如电子邮件地址,电话号码,等等。当用户获得一个联系人后,他会想要查看他的详细信息。你可以展示给他们所有的信息,或者只展示某一特定类型的信息,比如电子邮件地址。

这节课中,我们假设你已经有了用户选择的一行ContactsContract.Contacts联系人数据。在上一节课中(博客链接:http://www.cnblogs.com/jdneo/p/3674830.html)我们已经讲解了如何获取联系人列表的知识。


一). 获取一个联系人的详细信息

要获得一个联系人的所有信息,需要搜索ContactsContract.Data表的每一行,看是否包含有联系人的LOOKUP_KEY。这一列可在ContactsContract.Data中获得,因为Contacts Provider在ContactsContract.Contacts表和ContactsContract.Data表之间执行了一个隐式的连接。列LOOKUP_KEY的详细信息在上一节课中(博客链接:http://www.cnblogs.com/jdneo/p/3674830.html)已经讲授过了。

Note:

获取某一个联系人的所有信息会降低设备的性能,因为它需要获取ContactsContract.Data表中所有列的数据。在你使用这一方法前要考虑到它对性能的影响。

请求权限

要从Contacts Provider中读取数据,你的应用必须具有READ_CONTACTS权限。要请求这一权限,在清单文件的<manifest>标签中添加如下子标签:

<uses-permission android:name="android.permission.READ_CONTACTS" />

配置一个投影

根据每一行所包含的的数据类型,它可能使用一些列或很多列。另外,数据类型的不同会导致数据再不同的列中。要保证你能获得对于所有可能数据类型所对应的所有可能的列,你需要添加所有的列名到你的投影中。同时,如果要把结果Cursor和一个ListView绑定起来,要获取Data._ID;否则,绑定不会产生效果。同时要获取Data.MIMETYPE这样你就可以标示出你获得的每一行数据的类型,例如:

    private static final String PROJECTION =
{
Data._ID,
Data.MIMETYPE,
Data.DATA1,
Data.DATA2,
Data.DATA3,
Data.DATA4,
Data.DATA5,
Data.DATA6,
Data.DATA7,
Data.DATA8,
Data.DATA9,
Data.DATA10,
Data.DATA11,
Data.DATA12,
Data.DATA13,
Data.DATA14,
Data.DATA15
};

这一投影会为ContactsContract.Data表的一行获取所有的列,使用在ContactsContract.Data类中所定义的列名。

或者,你也可以是用在ContactsContract.Data类中定义或者从它继承的其它列常量。注意,列SYNC1到列SYNC4是被同步适配器使用的,所以他们的数据对我们现在的应用场景而言没有用。

定义选择标准

为你的选择语句定义一个常量,它是一个保存选择语句的数组,以及一个保存对应值的变量。使用Contacts.LOOKUP_KEY列来寻找联系人,例如:

    // Defines the selection clause
private static final String SELECTION = Data.LOOKUP_KEY + " = ?";
// Defines the array to hold the search criteria
private String[] mSelectionArgs = { "" };
/*
* Defines a variable to contain the selection value. Once you
* have the Cursor from the Contacts table, and you've selected
* the desired row, move the row's LOOKUP_KEY value into this
* variable.
*/
private String mLookupKey;

在你的选择语句中使用“?”作为占位符,能保证搜索语句是由绑定生成的而不是编译生成的。这可以防止恶意的SQL注入攻击。

定义排列顺序

为结果Cursor定义你期望的排列顺序。要让某一类型数据的所有行根据Data.MIMETYPE来排列。这一语句会让所有email的行放在一起,所有电话号码的行放在一起,等等。例如:

    /*
* Defines a string that specifies a sort order of MIME type
*/
private static final String SORT_ORDER = Data.MIMETYPE;

Note:

一些数据类型不使用子类,所以你不能用子类型来排序。相反的,你需要再返回的Cursor中进行迭代,确定当前行的数据类型,然后将使用子类型的行的数据保存起来。当你完成读cursor后,之后你就可以通过子类型排序并显示结果。

初始化加载器

通常,我们在后台线程从Contacts Provider(以及其它所有的内容提供器)获取数据。使用由LoaderManager类,以及LoaderManager.LoaderCallbacks接口所定义的加载器框架来执行后台的获取操作。

当你准备好获取行后,通过调用initLoader()初始化加载器框架。将一个整形标识传递给该方法;这一标志会传递给LoaderManager.LoaderCallbacks方法。它可以帮助你区分这些加载器,从而在一个应用中使用多个加载器。

下面的代码样例展示了如何初始化这个加载器框架:

public class DetailsFragment extends Fragment implements
LoaderManager.LoaderCallbacks<Cursor> {
...
// Defines a constant that identifies the loader
DETAILS_QUERY_ID = 0;
...
/*
* Invoked when the parent Activity is instantiated
* and the Fragment's UI is ready. Put final initialization
* steps here.
*/
@Override
onActivityCreated(Bundle savedInstanceState) {
...
// Initializes the loader framework
getLoaderManager().initLoader(DETAILS_QUERY_ID, null, this);

实现onCreateLoader()

实现onCreateLoader()方法,它会在你调用了initLoader()后被加载器框架调用。该方法返回一个CursorLoader。因为你在搜索ContactsContract.Data表,所以使用Data.CONTENT_URI常量作为内容URI。例如:

    @Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
// Choose the proper action
switch (loaderId) {
case DETAILS_QUERY_ID:
// Assigns the selection parameter
mSelectionArgs[0] = mLookupKey;
// Starts the query
CursorLoader mLoader =
new CursorLoader(
getActivity(),
Data.CONTENT_URI,
PROJECTION,
SELECTION,
mSelectionArgs,
SORT_ORDER
);
...
}

实现onLoadFinished()和onLoaderReset()

实现onLoadFinished()方法。当Contacts Provider将查询结果返回后,加载器框架会调用onLoadFinished()。例如:

    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
switch (loader.getId()) {
case DETAILS_QUERY_ID:
/*
* Process the resulting Cursor here.
*/
}
break;
...
}
}

当加载器检测到结果中的数据发生了变化,那么onLoaderReset()方法会被调用,此时,将所有存在的Cursor引用设置成null来移除它们。如果你不这么做,加载器框架不会销毁老的Cursor,这样会导致内存泄露,例如:

    @Override
public void onLoaderReset(Loader<Cursor> loader) {
switch (loader.getId()) {
case DETAILS_QUERY_ID:
/*
* If you have current references to the Cursor,
* remove them here.
*/
}
break;
}

二). 获取一个联系人的特定数据

要获取一个联系人的特定数据,比如email,和检索所有的详细数据类似,你需要做的改变仅仅是实现课程Retrieve All Details for a Contact(博客链接:http://www.cnblogs.com/jdneo/p/3674830.html中列出的代码:

投影

修改你的投影,使得列对应于特定的要搜索的数据类型。同时修改投影,使用在ContactsContract.CommonDataKinds子类中对应于数据类型的列常量名。

选择

修改选择语句,搜索对应于你的数据类型的MIMETYPE值。

排列顺序

因为你值使用单一的详细数据类型,所以不需要根据Data.MIMETYPE将返回的Cursor分类。

这些修改在下列章节中描述。

定义一个投影

定义你要获取的列,使用ContactsContract.CommonDataKinds子类中对应于数据类型的列常量名。如果你想要将Cursor绑定到一个ListView上,要确保获取“_ID”列。例如,要获取email数据,定义下列投影:

    private static final String[] PROJECTION =
{
Email._ID,
Email.ADDRESS,
Email.TYPE,
Email.LABEL
};

注意这一投影使用ContactsContract.CommonDataKinds.Email类中定义的列名,而不是在类ContactsContract.Data中定义的列名。使用email的特定列名可以增加代码的可读性。

在投影中,你也可以使用在ContactsContract.CommonDataKinds子类中定义的其它列。

定义选择标准

定义一个搜索表达式,它获取你想要的特定联系人的LOOKUP_KEYData.MIMETYPE行数据。对于MIMETYPE的值对应的常量,用单引号(')将它括起来;否则,提供器会把常量认为是一个变量名而不是一个字符串值。你不需要为它使用一个占位符,因为你使用的是一个常量而不是一个用户提供的值。例如:

    /*
* Defines the selection clause. Search for a lookup key
* and the Email MIME type
*/
private static final String SELECTION =
Data.LOOKUP_KEY + " = ?" +
" AND " +
Data.MIMETYPE + " = " +
"'" + Email.CONTENT_ITEM_TYPE + "'";
// Defines the array to hold the search criteria
private String[] mSelectionArgs = { "" };

定义排列顺序

为返回的Cursor定义一个排列顺序。因为你获得的是一个特定的数据类型,所以略过对MIMETYPE排序。另外,如果你正在搜索的详细数据包含有一个子类型,可以对他排序。例如,对于Email数据你可以根据Email.TYPE来排序:

    private static final String SORT_ORDER = Email.TYPE + " ASC ";

【Android Developers Training】 99. 获取联系人详细信息的更多相关文章

  1. 【Android Developers Training】 97. 序言:访问通讯录数据

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

  2. 【Android Developers Training】 98. 获取联系人列表

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

  3. 【Android Developers Training】 39. 获取文件信息

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

  4. 【Android Developers Training】 101. 显示快速联系人挂件(Quick Contact Badge)

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

  5. 【Android Developers Training】 100. 使用Intent修改联系人数据

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

  6. 【Android Developers Training】 95. 创建一个同步适配器

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

  7. 【Android Developers Training】 83. 实现高效网络访问来优化下载

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

  8. 【Android Developers Training】 80. 管理网络使用

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

  9. 【Android Developers Training】 75. 使用NSD

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

随机推荐

  1. java多线程面试总结

    一:基本知识点 1.1线程与进程区别: 1.进程是资源分配的最小单位,线程是CPU调度的最小单位 2.一个进程由一个或多个线程组成 3.进程之间相互独立,每个进程都有独立的代码和数据空间,但同一进程下 ...

  2. CentOS6.5下netcat工具安装教程

    1.下载下载地址:http://sourceforge.net/projects/netcat/files/netcat/0.7.1/下载的是netcat-0.7.1.tar.gz版本 2.拷贝用U盘 ...

  3. MyBatis源码解读(4)——SqlSession(上)

    在上一篇博客中提到MyBatis是如何实现代理类MapperProxy,并抛出了一个问题--是怎么执行一个具体的sql语句的,在文末中提到了MapperMethod的execute采用命令模式来判断是 ...

  4. html学习笔记 - 列表

    <!-- 无序列表 --> <ul type = square> <li><a href="https://www.baidu.com"& ...

  5. SVN分支/合并原理及最佳实践

    转自:http://blog.csdn.net/e3002/article/details/21469437 使用svn几年了,一直对分支和合并敬而远之,一来是因为分支的管理不该我操心,二来即使涉及到 ...

  6. 面试(1)-java-se-字符串

    http://blog.csdn.net/zhangerqing/article/details/8093919 hashCode和identityHashCode的区别 I. hashCode()方 ...

  7. ArrayList源码解析(四)

    这篇文章主要看ArrayList的Iterator和ListIterator的实现. 1.Iterator和类Itr 当我们调用iterator方法时返回一个Iterator. /** * Retur ...

  8. Docker容器管理平台Humpback进阶-私有仓库

    Docker私有仓库 在 Docker 中,当我们执行 docker pull xxx 的时候,可能会比较好奇,docker 会去哪儿查找并下载镜像呢? 它实际上是从 registry.hub.doc ...

  9. 你是否也在学习ES6 Promise时遇到过这个问题?

    背景 周末闲来无事,随便翻看了一下阮一峰老师的<ES6 标准入门>第2版,ps:之前在阮一峰老师的官网看过电子版,感觉干货满满,所以就买了纸质版:当看到第16章第4节 'Promise.p ...

  10. 使用外部容器运行spring-boot项目:不使用spring-boot内置容器让spring-boot项目运行在外部tomcat容器中

    前言:本项目基于maven构建 spring-boot项目可以快速构建web应用,其内置的tomcat容器也十分方便我们的测试运行: spring-boot项目需要部署在外部容器中的时候,spring ...