連絡先の詳細情報を取得する

このレッスンでは、メールアドレスや電話 番号など、連絡先の詳細データを取得する方法について説明します。ユーザーが連絡先を取得するときに探しているのは、詳細情報です。 連絡先のすべての詳細情報を表示することも、特定の種類の詳細情報のみを表示することもできます。 メールアドレスなど。

このレッスンの手順では、ユーザーが選択した連絡先の ContactsContract.Contacts 行がすでに存在することを前提としています。 連絡先のリストを取得する方法については、連絡先の名前を取得するレッスンをご覧ください。

連絡先のすべての詳細情報を取得する

連絡先のすべての詳細情報を取得するには、 ContactsContract.Data テーブルで連絡先の LOOKUP_KEY を含む行を検索します。連絡先プロバイダは ContactsContract.Contacts テーブルと ContactsContract.Data テーブルを暗黙的に結合するため、この列は ContactsContract.Data テーブルで使用できます。 LOOKUP_KEY 列の詳細については、連絡先の名前を取得するレッスンをご覧ください。

注: 連絡先のすべての詳細情報を取得すると、ContactsContract.Data テーブルのすべての列を取得する必要があるため、デバイスのパフォーマンスが低下します。この手法を使用する前に、パフォーマンスへの影響を考慮してください。 この手法を使用します。

権限をリクエスト

連絡先プロバイダから読み取るには、アプリに READ_CONTACTS 権限が必要です。 この権限をリクエストするには、マニフェスト ファイルに <manifest> の次の子要素を追加します:

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

射影をセットアップする

行に含まれるデータ型に応じて、使用する列の数は変わります。また、データはデータ型に応じて異なる列に格納されます。考えられるすべてのデータ型のすべての列を取得するには、すべての 列名を射影に追加する必要があります。結果の Cursor を ListView にバインドする場合は、必ず Data._ID を取得してください。そうしないと、バインド は機能しません。また、取得する各行のデータ型を識別できるように、Data.MIMETYPE も取得します。次に例を示します。

Kotlin

private val PROJECTION: Array<out String> = arrayOf(
        ContactsContract.Data._ID,
        ContactsContract.Data.MIMETYPE,
        ContactsContract.Data.DATA1,
        ContactsContract.Data.DATA2,
        ContactsContract.Data.DATA3,
        ContactsContract.Data.DATA4,
        ContactsContract.Data.DATA5,
        ContactsContract.Data.DATA6,
        ContactsContract.Data.DATA7,
        ContactsContract.Data.DATA8,
        ContactsContract.Data.DATA9,
        ContactsContract.Data.DATA10,
        ContactsContract.Data.DATA11,
        ContactsContract.Data.DATA12,
        ContactsContract.Data.DATA13,
        ContactsContract.Data.DATA14,
        ContactsContract.Data.DATA15
)

Java

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

この射影では、 ContactsContract.Data クラスで定義された列名を使用して、 ContactsContract.Data テーブルの行のすべての列を取得します。

必要に応じて、 ContactsContract.Data クラスで定義または継承された他の列定数を使用することもできます。ただし、 SYNC1 から SYNC4 までの列は同期 アダプターで使用することを目的としているため、そのデータは役に立ちません。

選択基準を定義する

選択句の定数、選択引数を保持する配列、選択値を保持する 変数を定義します。 Contacts.LOOKUP_KEY列を使用して連絡先を見つけます。次に例を示します。

Kotlin

// Defines the selection clause
private const val SELECTION: String = "${ContactsContract.Data.LOOKUP_KEY} = ?"
...
// Defines the array to hold the search criteria
private val selectionArgs: Array<String> = arrayOf("")
/*
 * 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 var lookupKey: String? = null

Java

    // Defines the selection clause
    private static final String SELECTION = Data.LOOKUP_KEY + " = ?";
    // Defines the array to hold the search criteria
    private String[] selectionArgs = { "" };
    /*
     * 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 lateinit var lookupKey: String

選択テキスト式で「?」をプレースホルダとして使用すると、結果の検索 は SQL コンパイルではなくバインディングによって生成されます。この方法では、 悪意のある SQL インジェクションの可能性が排除されます。

並べ替え順序を定義する

結果の Cursor で必要な並べ替え順序を定義します。特定のデータ型のすべての行をまとめるには、 Data.MIMETYPE で並べ替えます。このクエリ引数 は、すべてのメール行をグループ化し、すべての電話行をグループ化します。次に例を示します。

Kotlin

/*
 * Defines a string that specifies a sort order of MIME type
 */
private const val SORT_ORDER = ContactsContract.Data.MIMETYPE

Java

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

注: 一部のデータ型ではサブタイプを使用しないため、サブタイプで並べ替えることはできません。 代わりに、返された Cursor、 を反復処理して現在の行のデータ型を特定し、サブタイプを使用する行のデータを保存する必要があります。カーソルの読み取りが完了したら、各データ型をサブタイプで並べ替えて結果を表示できます。

ローダーを初期化する

連絡先プロバイダ(および他のすべてのコンテンツ プロバイダ)からの取得は、常に バックグラウンド スレッドで行います。バックグラウンド取得を行うには、 LoaderManager クラスと LoaderManager.LoaderCallbacks インターフェースで定義されたローダー フレームワークを使用します。

行を取得する準備ができたら、ローダー フレームワークを初期化して initLoader() を呼び出します。整数識別子をメソッドに渡します。この識別子は LoaderManager.LoaderCallbacks メソッドに渡されます。識別子を使用すると、アプリで複数のローダーを区別して使用できます。

次のスニペットは、ローダー フレームワークを初期化する方法を示しています。

Kotlin

// Defines a constant that identifies the loader
private const val DETAILS_QUERY_ID: Int = 0

class DetailsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        // Initializes the loader framework
        loaderManager.initLoader(DETAILS_QUERY_ID, null, this)

Java

public class DetailsFragment extends Fragment implements
        LoaderManager.LoaderCallbacks<Cursor> {
    ...
    // Defines a constant that identifies the loader
    static int DETAILS_QUERY_ID = 0;
    ...
    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        // Initializes the loader framework
        getLoaderManager().initLoader(DETAILS_QUERY_ID, null, this);

onCreateLoader() を実装する

onCreateLoader() メソッドを実装します。このメソッドは、 initLoader() を呼び出した直後にローダー フレームワークによって呼び出されます。このメソッドから CursorLoader を返します。`ContactsContract.Data` テーブルを検索しているため、コンテンツ URI として定数 `Data.CONTENT_URI` を使用します。次に例を示します。

Kotlin

override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> {
    // Choose the proper action
    mLoader = when(loaderId) {
        DETAILS_QUERY_ID -> {
            // Assigns the selection parameter
            selectionArgs[0] = lookupKey
            // Starts the query
            activity?.let {
                CursorLoader(
                        it,
                        ContactsContract.Data.CONTENT_URI,
                        PROJECTION,
                        SELECTION,
                        selectionArgs,
                        SORT_ORDER
                )
            }
        }
        ...
    }
    return mLoader
}

Java

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

onLoadFinished() と onLoaderReset() を実装する

onLoadFinished() メソッドを実装します。連絡先プロバイダがクエリの結果を返すと、ローダー フレームワークは onLoadFinished() を呼び出します。次に例を示します。

Kotlin

    override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor) {
        when(loader.id) {
            DETAILS_QUERY_ID -> {
                /*
                 * Process the resulting Cursor here.
                 */
            }
            ...
        }
    }

Java

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

ローダー フレームワークが結果の Cursor をバックアップするデータが変更されたことを検出すると、メソッド onLoaderReset() が呼び出されます。この時点で、既存の参照 をCursor null に設定して削除します。そうしないと、ローダー フレームワークは古い Cursor を破棄せず、メモリ リークが発生します。次に例を示します。

Kotlin

    override fun onLoaderReset(loader: Loader<Cursor>) {
        when (loader.id) {
            DETAILS_QUERY_ID -> {
                /*
                 * If you have current references to the Cursor,
                 * remove them here.
                 */
            }
            ...
        }
    }

Java

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

連絡先の特定の詳細情報を取得する

連絡先の特定のデータ型(すべてのメールなど)を取得する手順は、すべての詳細情報を取得する場合と 同じです。 連絡先のすべての詳細情報を取得するに記載されているコード に対して行う必要がある変更は次のとおりです。

射影
データ型に固有の列を取得するように射影を変更します。 また、データ型に対応する ContactsContract.CommonDataKinds サブクラスで定義された列名定数を使用するように射影を変更します。
選択
選択テキストを変更して、 MIMETYPE データ型に固有の値を検索します。
並べ替え順
1 種類の詳細情報のみを選択しているため、返されたCursor を Data.MIMETYPE でグループ化しないでください。

これらの変更については、次のセクションで説明します。

プロジェクションを定義する

データ型の ContactsContract.CommonDataKinds サブクラスの列名定数を使用して、取得する列を定義します。Cursor を ListView にバインドする場合は、必ず _ID 列を取得してください。たとえば、メールデータを取得するには、次のように射影を定義します。

Kotlin

private val PROJECTION: Array<String> = arrayOf(
        ContactsContract.CommonDataKinds.Email._ID,
        ContactsContract.CommonDataKinds.Email.ADDRESS,
        ContactsContract.CommonDataKinds.Email.TYPE,
        ContactsContract.CommonDataKinds.Email.LABEL
)

Java

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

この射影では、クラス ContactsContract.Data で定義された列名ではなく、クラス ContactsContract.CommonDataKinds.Email で定義された列名を使用します。メール固有の 列名を使用すると、コードが読みやすくなります。

射影では、 ContactsContract.CommonDataKinds サブクラスで定義されている他の列も使用できます。

選択基準を定義する

特定の連絡先の LOOKUP_KEY と必要な詳細情報の Data.MIMETYPE の行を取得する検索テキスト式を定義します。定数の先頭と末尾に「'」(一重引用符)文字を連結して、MIMETYPE値を一重引用符で囲みます。そうしないと、プロバイダは定数を文字列値ではなく変数名として解釈します。ユーザーが指定した値ではなく定数を使用しているため、この値にプレースホルダを使用する必要はありません。次に例を示します。

Kotlin

/*
 * Defines the selection clause. Search for a lookup key
 * and the Email MIME type
 */
private const val SELECTION =
        "${ContactsContract.Data.LOOKUP_KEY} = ? AND " +
        "${ContactsContract.Data.MIMETYPE} = '${Email.CONTENT_ITEM_TYPE}'"
...
// Defines the array to hold the search criteria
private val selectionArgs: Array<String> = arrayOf("")

Java

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

並べ替え順序を定義する

返された Cursor の並べ替え順序を定義します。特定のデータ型を取得しているため、MIMETYPE での並べ替えは省略します。代わりに、検索する詳細データの種類にサブタイプが含まれている場合は、サブタイプで並べ替えます。 たとえば、メールデータの場合は Email.TYPEで並べ替えることができます。

Kotlin

private const val SORT_ORDER: String = "${Email.TYPE} ASC"

Java

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