Android 獲取聯(lián)系人詳情

2018-08-02 17:46 更新

編寫:spencer198711 - 原文:http://developer.android.com/training/contacts-provider/retrieve-details.html

這一課展示了如何取得一個(gè)聯(lián)系人的詳細(xì)信息,比如email地址、電話號(hào)碼等。當(dāng)使用者去獲取聯(lián)系人信息的時(shí)候,這些信息正是他們所查找的。我們可以給他們關(guān)于一個(gè)聯(lián)系人的所有信息,或者僅僅顯示一個(gè)特定的數(shù)據(jù)類型,比如email地址。

這一課假設(shè)你已經(jīng)獲取到了一個(gè)用戶所選取的聯(lián)系人的ContactsContract.Contacts數(shù)據(jù)項(xiàng)。在獲取聯(lián)系人名字那一課展示了如何獲取聯(lián)系人列表。

獲取聯(lián)系人的所有詳細(xì)信息

為了取得一個(gè)聯(lián)系人的所有詳情,查找ContactsContract.Data表中包含聯(lián)系人LOOKUP_KEY列的任意行。因?yàn)镃ontacts Provider隱式地連接了ContactsContract.Contacts表和ContactsContract.Data表,所以這個(gè)LOOKUP_KEY列在ContactsContract.Data表中是可用的。關(guān)于LOOKUP_KEY列,在獲取聯(lián)系人名字那一課有詳細(xì)的描述。

Note:檢索一個(gè)聯(lián)系人的所有信息會(huì)降低設(shè)備的性能,因?yàn)檫@需要檢索ContactsContract.Data表的所有列。在使用這種方法之前,請(qǐng)認(rèn)真考慮對(duì)性能影響。

請(qǐng)求權(quán)限

為了能夠讀Contacts Provider,我們的應(yīng)用必須擁有READ_CONTACTS權(quán)限。為了請(qǐng)求這個(gè)權(quán)限,需要在manifest文件的中添加如下子節(jié)點(diǎn):

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

設(shè)置查詢映射

根據(jù)一行數(shù)據(jù)的數(shù)據(jù)類型,它可能會(huì)使用很多列或者只使用幾列。另外,數(shù)據(jù)會(huì)根據(jù)不同的數(shù)據(jù)類型而出現(xiàn)在不同的列中。為了確保能夠獲取所有數(shù)據(jù)類型的所有可能的數(shù)據(jù)列,需要在查詢映射中添加所有列的名字。如果要把Cursor綁定到ListView,記得要獲取Data._ID,否則的話,界面綁定就不會(huì)起作用。同時(shí)也需要獲取Data.MIMETYPE列,這樣才能識(shí)別我們獲取到的每一行數(shù)據(jù)的數(shù)據(jù)類型。例如:

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
            };

這個(gè)查詢映射使用了ContactsContract.Data類中定義的列名字,去獲取ContactsContract.Data表中一行的所有數(shù)據(jù)列。

我們也可以使用由ContactsContract.Data或其子類定義的列常量去設(shè)置查詢映射。需要注意的是,從SYNC1到SYNC4的數(shù)據(jù)列是sync adapter同步數(shù)據(jù)所使用的,它們的值對(duì)我們沒有意義。

定義查詢標(biāo)準(zhǔn)

為查詢選擇子句定義一個(gè)常量,一個(gè)包含查詢選擇參數(shù)的數(shù)組,以及一個(gè)保存查詢選擇值的變量。使用Contacts.LOOKUP_KEY列去查找這個(gè)聯(lián)系人。例如:

    // 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;

在查詢選擇表達(dá)式中使用 “?”占位符,確保了搜索是由綁定生成而不是由SQL編譯生成。這種方法消除了惡意SQL注入的可能性。

定義排序順序

定義在查詢結(jié)果Cursor中希望的排序順序。按照Data.MIMETYPE去排序,可以讓特定數(shù)據(jù)類型的所有行排列在一起。這種形式的查詢排序參數(shù)讓所有具有email的行排在一起,讓所有具有電話的行排在一起……例如:

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

Note:一些數(shù)據(jù)類型不使用子類型,所以不能按照子類型來排序。作為替代方法,我們不得不遍歷返回的Cursor,去判定當(dāng)前行的數(shù)據(jù)類型,為那些使用子類型的數(shù)據(jù)行保存數(shù)據(jù)。當(dāng)讀取完cursor后,我們可以根據(jù)子類型去排序每一個(gè)數(shù)據(jù)類型并顯示結(jié)果。

初始化查詢loader

永遠(yuǎn)在后臺(tái)線程中去檢索Contacts Provider(或者其他content provider)的數(shù)據(jù)。使用Loader框架中的LoaderManager類和LoaderManager.LoaderCallbacks在后臺(tái)去做獲取數(shù)據(jù)的工作。

當(dāng)我們已經(jīng)準(zhǔn)備好去獲取數(shù)據(jù)行,需要通過調(diào)用initLoader()方法去初始化loader框架。傳遞一個(gè)Integer類型的標(biāo)識(shí)符給initLoader()方法,這個(gè)標(biāo)識(shí)符會(huì)傳遞給LoaderManager.LoaderCallbacks方法。當(dāng)在一個(gè)應(yīng)用中使用多個(gè)loader時(shí),這個(gè)標(biāo)識(shí)符能夠幫助我們區(qū)分它們。

以下的代碼片段展示了如何初始化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);

實(shí)現(xiàn)onCreateLoader()方法

實(shí)現(xiàn)onCreateLoader()方法。loader框架會(huì)在我們調(diào)用initLoader()方法后立即調(diào)用onCreateLoader()方法。這個(gè)方法會(huì)返回一個(gè)CursorLoader對(duì)象。由于搜索的是ContactsContract.Data表,所以需要使用常量Data.CONTENT_URI作為內(nèi)容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
                    );
            ...
    }

實(shí)現(xiàn)onLoadFinished()方法和onLoaderReset()方法

實(shí)現(xiàn)onLoadFinished()方法。當(dāng)Contacts Provider返回查詢結(jié)果的時(shí)候,loader框架會(huì)調(diào)用onLoadFinished()方法。例如:

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

當(dāng)loader框架檢測(cè)到結(jié)果集Cursor所對(duì)應(yīng)的數(shù)據(jù)已經(jīng)發(fā)生變化的時(shí)候,會(huì)調(diào)用onLoaderReset()方法。這時(shí),需要通過把Cursor設(shè)置為null來移除對(duì)已經(jīng)存在Cursor對(duì)象的引用。否則,loader框架就不會(huì)銷毀舊的Cursor對(duì)象,從而導(dǎo)致內(nèi)存泄漏。例如:

    @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;
    }

獲取聯(lián)系人的特定類型的信息

獲取聯(lián)系人的特定類型的信息,例如所有的email信息,跟獲取聯(lián)系人的所有詳細(xì)信息類似。下面的內(nèi)容是在獲取聯(lián)系人的所有詳細(xì)信息列出的代碼的基礎(chǔ)上作出的修改:

查詢映射

修改查詢映射使得能夠針對(duì)特定的數(shù)據(jù)類型去獲取列。同時(shí)需要修改查詢映射,來把在ContactsContract.CommonDataKinds子類中定義的列常量與數(shù)據(jù)類型對(duì)應(yīng)起來。

查詢選擇

修改查詢選擇子句去搜索特定類型的MIMETYPE值。

排序順序

由于僅僅搜索一種類型的詳細(xì)數(shù)據(jù),所以不需要將返回的Cursor按照Data.MIMETYPE進(jìn)行分組。

這些修改將會(huì)在下面的小節(jié)中詳細(xì)描述。

設(shè)置查詢映射

使用ContactsContract.CommonDataKinds的特定類型子類所定義的列名稱常量,定義我們想要獲取的數(shù)據(jù)列。如果我們打算把Cursor綁定到ListView,確保要獲取_ID列。例如,為了獲取email數(shù)據(jù),需要定義以下數(shù)據(jù)映射:

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

需要注意的是,這個(gè)查詢映射使用在ContactsContract.CommonDataKinds.Email類中定義的列名稱,來替代ContactsContract.Data類中定義的列名稱。使用email類型的列名稱使得代碼更具可讀性。

在查詢映射中,我們也可以使用ContactsContract.CommonDataKinds子類所定義的其他數(shù)據(jù)列。

定義查詢標(biāo)準(zhǔn)

根據(jù)我們想要找的特定聯(lián)系人的LOOKUP_KEY和聯(lián)系人詳細(xì)信息的Data.MIMETYPE定義一個(gè)搜索表達(dá)式,去獲取數(shù)據(jù)。把MIMETYPE的值從頭到尾用單引號(hào)括住,否則的話,content provider將會(huì)把這個(gè)常量當(dāng)成變量名而不是字符串。因?yàn)槲覀兪褂玫氖浅A?,而不是用戶提供的值,所以這里不需要使用占位符。例如:

/*
     * 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 = { "" };

定義排序規(guī)則

為查詢返回的Cursor定義一個(gè)排序規(guī)則。由于是檢索特定的數(shù)據(jù)類型,刪除根據(jù)MIMETYPE來排序的部分。而如果查詢的詳細(xì)數(shù)據(jù)類型包含子類型,可以根據(jù)這個(gè)子類型去排序。例如,對(duì)于email數(shù)據(jù),我們可以根據(jù)Email.TYPE排序:

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


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)