通讯录数据的存取(二)—— 获取通讯录的具体信息

获取通讯录的具体信息

这一节展示如何获取联系人的具体信息,如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 ";
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值