获取通讯录的具体信息
这一节展示如何获取联系人的具体信息,如email地址,电话号码等。首先假设你已经阅读过通讯录数据的存取(一)——获取通讯录列表, 获取了通讯录列表。
分两节:
- 获取联系人的所有信息
- 获取联系人的某类型信息
获取联系人的所有信息
实现方案是搜索ContactsContract.Data表中包含联系人的LOOKUP_KEY的所有行。Contacts Provider会对ContactsContract.Data表和ContactsContract.Contacts表做一个连接,因此LOOKUP_KEY这一列也可以在ContactsContract.Data表中找到。
申请权限:
<uses-permission android:name="android.permission.READ_CONTACTS" />
设置一个规划(projection)
根据数据类型的不同,Data表中的一行可能只使用某些列。数据类型不同,使用的列也不同。为保证获取所有可能的数据类型,需要将所有的列名都添加到规划中。如果需要将结果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
};
定义选择标准
定义一个选择预计常量,一个包含搜索参数的数列,一个保存待搜索值的变量。使用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编译来生成,避免恶意SQL注入的可能性。
使用变量来表示待搜索的内容,即SQL中替换“?”的内容。
定义排序方式
定义搜索结果的排序方式。如想让每种类型的数据在一起,可以使用Data.MIME来排序。这样结果中所有的email类型数据的行在一起,所有的电话类型数据的行在一起。如下:
/*
* Defines a string that specifies a sort order of MIME type
*/
private static final String SORT_ORDER = Data.MIMETYPE;
初始化CursorLoader
获取Contacts Provider数据的过程必须在后台线程中进行。使用Loader框架可以实现后台获取。它包含LoaderManager类和LoaderManager.LoaderCallbacks接口.
当准备获取数据时,先通过调用initLoader()初始化loader框架.需要传输一个整型参数给该方法,该参数会传递给LoaderManager.LoaderCallbacks方法。在同一个应用程序包含多个loader的情况下,可以使用该参数区分不同的loader。
代码如下:
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()
该方法会在我们调用initLoader()后立即被loader框架调用。
因为搜索的是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
);
...
}
其中DETAILS_QUERY_ID正是上一节中传递的整型参数。
实现onLoadFinished()和onLoadReset()
Loader框架在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()方法会在loader框架发现Cursor结果的数据发生改变时被调用。在该方法中,需要清除所有对上述Cursor的引用,否则loader框架不会回收该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,按照上一节的步骤执行,只需修改一下几项:
规划(Projection): 修改只获取某类型的列。 使用ContactsContract.CommonDataKinds的与类型匹配的子类的列名常量。
选择(Selection):添加MIMETYPE值的搜索语句。
排序(Sort order):无需根据Data.MIMETYPE对搜索结果cursor进行排序。
定义一个规划(projection)
使用ContactsContract.CommonDataKinds的与类型匹配的子类的列名常量。如:
private static final String[] PROJECTION =
{
Email._ID,
Email.ADDRESS,
Email.TYPE,
Email.LABEL
};
上述关于获取Email数据的规划,使用了ContactsContract.CommonDataKinds.Email类定义的列名,而没有使用ContactsContract.Data类的列名,前者可读性更强。
定义选择标准
定义一个使用LOOKUP_KEY和Data.MIMETYPE的搜索语句。 需要使用单引号将搜索数据类型对应的MIMETYPE值括起来,否则provider会把它当作变量名而不是常量。 代码如下:
/*
* 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 = { "" };
定义排序方式
忽略根据Data.MIMETYPE对搜索结果cursor进行排序。如果待搜索数据的类型包含子类的话,可以使用该子类来排序。例如以Email.TYPE排序:
private static final String SORT_ORDER = Email.TYPE + " ASC ";