クイック コンタクト バッジを表示する

このレッスンでは、UI に QuickContactBadge を追加する方法と、それにデータをバインドする方法について説明します。QuickContactBadge は、初期状態ではサムネイル画像として表示されるウィジェットです。任意の Bitmap をサムネイル画像として使用できますが、通常は、連絡先の写真のサムネイル画像からデコードした Bitmap を使用します。

小さな画像はコントロールとして機能します。ユーザーがこの画像をタップすると、QuickContactBadge が、以下を含むダイアログに展開されます。

大きな画像
連絡先に関連付けられた大きな画像。利用可能な画像がない場合は、プレースホルダ グラフィックが表示されます。
アプリアイコン
内蔵アプリによって処理可能な各詳細データ用のアプリアイコン。たとえば、連絡先情報に 1 つまたは複数のメールアドレスが含まれている場合、メールアイコンが表示されます。ユーザーがアイコンをタップすると、連絡先のすべてのメールアドレスが表示されます。ユーザーがいずれかのメールアドレスをタップすると、選択したメールアドレス宛てにメールを作成するための画面がメールアプリに表示されます。

QuickContactBadge ビューを使用すると、連絡先情報にすばやくアクセスして、簡単に連絡先とコミュニケーションを取ることができます。ユーザーは、連絡先を検索して、情報を見つけてコピーし、適切なアプリに貼り付ける必要はありません。代わりに、QuickContactBadge をタップして、使用する連絡方法を選択すれば、その情報を適切なアプリに直接送信することができます。

QuickContactBadge ビューを追加する

QuickContactBadge を追加するには、レイアウトに <QuickContactBadge> 要素を挿入します。たとえば、次のようになります。

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">
    ...
        <QuickContactBadge
                   android:id=@+id/quickbadge
                   android:layout_height="wrap_content"
                   android:layout_width="wrap_content"
                   android:scaleType="centerCrop"/>
        ...
    </RelativeLayout>
    

プロバイダ データを取得する

QuickContactBadge 内に連絡先を表示するには、連絡先のコンテンツ URI と小さな画像用の Bitmap が必要です。連絡先プロバイダから取得した列から、コンテンツ URI と Bitmap の両方を生成します。データを Cursor にロードする際に使用する代替表記の一部として、上記の列を指定します。

Android 3.0(API レベル 11)以降の場合、次の列を代替表記に含めます。

Android 2.3.3(API レベル 10)以前の場合、次の列を使用します。

以下では、上記の列や他の選択列を格納する Cursor をすでにロードしていることを前提としています。Cursor 内で上記の列を取得する方法については、連絡先のリストを取得するをご覧ください。

連絡先 URI とサムネイルを設定する

必要な列を取得したら、データを QuickContactBadge にバインドできます。

連絡先 URI を設定する

連絡先のコンテンツ URI を設定するには、getLookupUri(id,lookupKey) を呼び出して CONTENT_LOOKUP_URI を取得し、assignContactUri() を呼び出して連絡先を設定します。たとえば、次のようになります。

Kotlin

        // The Cursor that contains contact rows
        var mCursor: Cursor? = null
        // The index of the _ID column in the Cursor
        var idColumn: Int = 0
        // The index of the LOOKUP_KEY column in the Cursor
        var lookupKeyColumn: Int = 0
        // A content URI for the desired contact
        var contactUri: Uri? = null
        // A handle to the QuickContactBadge view
        lateinit var mBadge: QuickContactBadge
        ...
        mBadge = findViewById(R.id.quickbadge)

        mCursor?.let { cursor ->
            /*
             * Insert code here to move to the desired cursor row
             */
            // Gets the _ID column index
            idColumn = cursor.getColumnIndex(ContactsContract.Contacts._ID)
            // Gets the LOOKUP_KEY index
            lookupKeyColumn = cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)
            // Gets a content URI for the contact
            contactUri = ContactsContract.Contacts.getLookupUri(
                    cursor.getLong(idColumn),
                    cursor.getString(lookupKeyColumn)
            )
            mBadge.assignContactUri(contactUri)
        }
    

Java

        // The Cursor that contains contact rows
        Cursor mCursor;
        // The index of the _ID column in the Cursor
        int idColumn;
        // The index of the LOOKUP_KEY column in the Cursor
        int lookupKeyColumn;
        // A content URI for the desired contact
        Uri contactUri;
        // A handle to the QuickContactBadge view
        QuickContactBadge mBadge;
        ...
        mBadge = (QuickContactBadge) findViewById(R.id.quickbadge);
        /*
         * Insert code here to move to the desired cursor row
         */
        // Gets the _ID column index
        idColumn = mCursor.getColumnIndex(ContactsContract.Contacts._ID);
        // Gets the LOOKUP_KEY index
        lookupKeyColumn = mCursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY);
        // Gets a content URI for the contact
        contactUri =
                Contacts.getLookupUri(
                    mCursor.getLong(idColumn),
                    mCursor.getString(lookupKeyColumn)
                );
        mBadge.assignContactUri(contactUri);
    

ユーザーが QuickContactBadge アイコンをタップすると、連絡先情報が自動的にダイアログに表示されます。

写真のサムネイルを設定する

QuickContactBadge 用の連絡先 URI を設定しても、連絡先のサムネイル写真が自動的にロードされることはありません。写真をロードするには、連絡先の Cursor 行から写真の URI を取得し、それを使用して圧縮サムネイル写真を含むファイルを開き、そのファイルを Bitmap に読み取ります。

注: PHOTO_THUMBNAIL_URI 列は、3.0 以前のバージョンのプラットフォームでは利用できません。このようなバージョンの場合、Contacts.Photo サブテーブルから URI を取得する必要があります。

まず、上記で説明したように、Contacts._ID 列と Contacts.LOOKUP_KEY 列を格納する Cursor にアクセスするための変数をセットアップします。

Kotlin

        // The column in which to find the thumbnail ID
        var thumbnailColumn: Int = 0
        /*
         * The thumbnail URI, expressed as a String.
         * Contacts Provider stores URIs as String values.
         */
        var thumbnailUri: String? = null
        ...
        mCursor?.let { cursor ->
            /*
             * Gets the photo thumbnail column index if
             * platform version >= Honeycomb
             */
            thumbnailColumn = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_THUMBNAIL_URI)
                // Otherwise, sets the thumbnail column to the _ID column
            } else {
                idColumn
            }
            /*
             * Assuming the current Cursor position is the contact you want,
             * gets the thumbnail ID
             */
            thumbnailUri = cursor.getString(thumbnailColumn)
        }
    

Java

        // The column in which to find the thumbnail ID
        int thumbnailColumn;
        /*
         * The thumbnail URI, expressed as a String.
         * Contacts Provider stores URIs as String values.
         */
        String thumbnailUri;
        ...
        /*
         * Gets the photo thumbnail column index if
         * platform version >= Honeycomb
         */
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            thumbnailColumn =
                    cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_THUMBNAIL_URI);
        // Otherwise, sets the thumbnail column to the _ID column
        } else {
            thumbnailColumn = idColumn;
        }
        /*
         * Assuming the current Cursor position is the contact you want,
         * gets the thumbnail ID
         */
        thumbnailUri = cursor.getString(thumbnailColumn);
        ...
    

連絡先の写真関連データと、宛先ビューのサイズを取得し、適切なサイズのサムネイルを Bitmap に返すメソッドを定義します。まず、サムネイルをポイントする URI を作成するところから始めます。

Kotlin

        /**
         * Load a contact photo thumbnail and return it as a Bitmap,
         * resizing the image to the provided image dimensions as needed.
         * @param photoData photo ID Prior to Honeycomb, the contact's _ID value.
         * For Honeycomb and later, the value of PHOTO_THUMBNAIL_URI.
         * @return A thumbnail Bitmap, sized to the provided width and height.
         * Returns null if the thumbnail is not found.
         */
        private fun loadContactPhotoThumbnail(photoData: String): Bitmap? {
            // Creates an asset file descriptor for the thumbnail file.
            var afd: AssetFileDescriptor? = null
            // try-catch block for file not found
            try {
                // Creates a holder for the URI.
                val thumbUri: Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                    // If Android 3.0 or later
                    // Sets the URI from the incoming PHOTO_THUMBNAIL_URI
                    Uri.parse(photoData)
                } else {
                    // Prior to Android 3.0, constructs a photo Uri using _ID
                    /*
                     * Creates a contact URI from the Contacts content URI
                     * incoming photoData (_ID)
                     */
                    val contactUri: Uri =
                            Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, photoData)
                    /*
                     * Creates a photo URI by appending the content URI of
                     * Contacts.Photo.
                     */
                    Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY)
                }

                /*
                 * Retrieves an AssetFileDescriptor object for the thumbnail
                 * URI
                 * using ContentResolver.openAssetFileDescriptor
                 */
                afd = activity?.contentResolver?.openAssetFileDescriptor(thumbUri, "r")
                /*
                 * Gets a file descriptor from the asset file descriptor.
                 * This object can be used across processes.
                 */
                return afd?.fileDescriptor?.let {fileDescriptor ->
                    // Decode the photo file and return the result as a Bitmap
                    // If the file descriptor is valid
                    BitmapFactory.decodeFileDescriptor(fileDescriptor, null, null)
                }
            } catch (e: FileNotFoundException) {
                /*
                 * Handle file not found errors
                 */
                null
            } finally {
                // In all cases, close the asset file descriptor
                try {
                    afd?.close()
                } catch (e: IOException) {
                }
            }
        }
    

Java

        /**
         * Load a contact photo thumbnail and return it as a Bitmap,
         * resizing the image to the provided image dimensions as needed.
         * @param photoData photo ID Prior to Honeycomb, the contact's _ID value.
         * For Honeycomb and later, the value of PHOTO_THUMBNAIL_URI.
         * @return A thumbnail Bitmap, sized to the provided width and height.
         * Returns null if the thumbnail is not found.
         */
        private Bitmap loadContactPhotoThumbnail(String photoData) {
            // Creates an asset file descriptor for the thumbnail file.
            AssetFileDescriptor afd = null;
            // try-catch block for file not found
            try {
                // Creates a holder for the URI.
                Uri thumbUri;
                // If Android 3.0 or later
                if (Build.VERSION.SDK_INT
                        >=
                    Build.VERSION_CODES.HONEYCOMB) {
                    // Sets the URI from the incoming PHOTO_THUMBNAIL_URI
                    thumbUri = Uri.parse(photoData);
                } else {
                // Prior to Android 3.0, constructs a photo Uri using _ID
                    /*
                     * Creates a contact URI from the Contacts content URI
                     * incoming photoData (_ID)
                     */
                    final Uri contactUri = Uri.withAppendedPath(
                            ContactsContract.Contacts.CONTENT_URI, photoData);
                    /*
                     * Creates a photo URI by appending the content URI of
                     * Contacts.Photo.
                     */
                    thumbUri =
                            Uri.withAppendedPath(
                                    contactUri, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
                }

            /*
             * Retrieves an AssetFileDescriptor object for the thumbnail
             * URI
             * using ContentResolver.openAssetFileDescriptor
             */
            afd = getActivity().getContentResolver().
                    openAssetFileDescriptor(thumbUri, "r");
            /*
             * Gets a file descriptor from the asset file descriptor.
             * This object can be used across processes.
             */
            FileDescriptor fileDescriptor = afd.getFileDescriptor();
            // Decode the photo file and return the result as a Bitmap
            // If the file descriptor is valid
            if (fileDescriptor != null) {
                // Decodes the bitmap
                return BitmapFactory.decodeFileDescriptor(
                        fileDescriptor, null, null);
                }
            // If the file isn't found
            } catch (FileNotFoundException e) {
                /*
                 * Handle file not found errors
                 */
            // In all cases, close the asset file descriptor
            } finally {
                if (afd != null) {
                    try {
                        afd.close();
                    } catch (IOException e) {}
                }
            }
            return null;
        }
    

コード内で loadContactPhotoThumbnail() メソッドを呼び出して、サムネイル Bitmap を取得し、その結果を使用して QuickContactBadge 内に写真のサムネイルを設定します。

Kotlin

        ...
        /*
         * Decodes the thumbnail file to a Bitmap.
         */
        mThumbnailUri?.also { thumbnailUri ->
            loadContactPhotoThumbnail(thumbnailUri).also { thumbnail ->
                /*
                 * Sets the image in the QuickContactBadge
                 * QuickContactBadge inherits from ImageView, so
                 */
                badge.setImageBitmap(thumbnail)
            }
        }
    

Java

        ...
        /*
         * Decodes the thumbnail file to a Bitmap.
         */
        Bitmap mThumbnail =
                loadContactPhotoThumbnail(thumbnailUri);
        /*
         * Sets the image in the QuickContactBadge
         * QuickContactBadge inherits from ImageView, so
         */
        badge.setImageBitmap(mThumbnail);
    

QuickContactBadge を ListView に追加する

QuickContactBadge は、連絡先のリストを表示する ListView に追加された便利な機能です。QuickContactBadge を使用すると、各連絡先のサムネイル写真を表示できます。ユーザーがサムネイルをタップすると、QuickContactBadge ダイアログが表示されます。

QuickContactBadge 要素を追加する

まず、アイテム レイアウトに QuickContactBadge ビュー要素を追加します。たとえば、QuickContactBadge と、取得する各連絡先の名前を表示する場合は、レイアウト ファイル内に次の XML を配置します。

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">
        <QuickContactBadge
            android:id="@+id/quickcontact"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:scaleType="centerCrop"/>
        <TextView android:id="@+id/displayname"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:layout_toRightOf="@+id/quickcontact"
                  android:gravity="center_vertical"
                  android:layout_alignParentRight="true"
                  android:layout_alignParentTop="true"/>
    </RelativeLayout>
    

以降のセクションでは、このファイルのことを contact_item_layout.xml と呼びます。

カスタム CursorAdapter をセットアップする

QuickContactBadge を格納する ListViewCursorAdapter をバインドするには、CursorAdapter を拡張するカスタム アダプターを定義します。このアプローチにより、QuickContactBadge にバインドする前に Cursor 内のデータを処理できるようになります。また、このアプローチの場合、複数の Cursor 列を QuickContactBadge にバインドすることもできます。通常の CursorAdapter の場合、どちらの処理も実行できません。

定義する CursorAdapter のサブクラスは、次のメソッドをオーバーライドする必要があります。

CursorAdapter.newView()
新しい View オブジェクトをインフレートして、アイテム レイアウトを保持します。このメソッドのオーバーライドで、レイアウトの子 View オブジェクト(子 QuickContactBadge を含む)のハンドルを格納します。このアプローチにより、新しいレイアウトをインフレートするたびに子 View オブジェクトのハンドルを取得する必要がなくなります。

View オブジェクトのハンドルを個々に取得できるように、このメソッドをオーバーライドする必要があります。この方法により、CursorAdapter.bindView() のバインディングを制御できます。

CursorAdapter.bindView()
データを現在の Cursor 行からアイテム レイアウトの子 View オブジェクトに移動します。連絡先 URI とサムネイルの両方を QuickContactBadge にバインドできるように、このメソッドをオーバーライドする必要があります。デフォルト実装の場合、列と View との間で 1 対 1 のマッピングしか許可されません。

CursorAdapter のカスタム サブクラスの例を下記のコード スニペットに示します。

カスタム リスト アダプターを定義する

コンストラクタを含む CursorAdapter のサブクラスを定義し、newView()bindView() をオーバーライドします。

Kotlin

        /**
         * Defines a class that hold resource IDs of each item layout
         * row to prevent having to look them up each time data is
         * bound to a row.
         */
        private data class ViewHolder(
                internal var displayname: TextView? = null,
                internal var quickcontact: QuickContactBadge? = null
        )

        /**
         *
         *
         */
        private inner class ContactsAdapter(
                context: Context,
                val inflater: LayoutInflater = LayoutInflater.from(context)
        ) : CursorAdapter(context, null, 0) {
            ...
            override fun newView(
                    context: Context,
                    cursor: Cursor,
                    viewGroup: ViewGroup
            ): View {
                /* Inflates the item layout. Stores resource IDs in a
                 * in a ViewHolder class to prevent having to look
                 * them up each time bindView() is called.
                 */
                return inflater.inflate(
                        R.layout.contact_list_layout,
                        viewGroup,
                        false
                ).also { view ->
                    view.tag = ViewHolder().apply {
                        displayname = view.findViewById(R.id.displayname)
                        quickcontact = view.findViewById(R.id.quickcontact)
                    }
                }
            }

            ...

            override fun bindView(view: View?, context: Context?, cursor: Cursor?) {
                (view?.tag as? ViewHolder)?.also { holder ->
                    cursor?.apply {
                        ...
                        // Sets the display name in the layout
                        holder.displayname?.text = getString(displayNameIndex)
                        ...
                        /*
                         * Generates a contact URI for the QuickContactBadge.
                         */
                        ContactsContract.Contacts.getLookupUri(
                                getLong(idIndex),
                                cursor.getString(lookupKeyIndex)
                        ).also { contactUri ->
                            holder.quickcontact?.assignContactUri(contactUri)
                        }

                        getString(photoDataIndex)?.also {photoData ->
                            /*
                             * Decodes the thumbnail file to a Bitmap.
                             * The method loadContactPhotoThumbnail() is defined
                             * in the section "Set the Contact URI and Thumbnail"
                             */
                            loadContactPhotoThumbnail(photoData)?.also { thumbnailBitmap ->
                                /*
                                 * Sets the image in the QuickContactBadge
                                 * QuickContactBadge inherits from ImageView
                                 */
                                holder.quickcontact?.setImageBitmap(thumbnailBitmap)
                            }
                        }
                    }
                }

            }
        }
    

Java

        private class ContactsAdapter extends CursorAdapter {
            private LayoutInflater mInflater;
            ...
            public ContactsAdapter(Context context) {
                super(context, null, 0);

                /*
                 * Gets an inflater that can instantiate
                 * the ListView layout from the file.
                 */
                mInflater = LayoutInflater.from(context);
                ...
            }
            ...
            /**
             * Defines a class that hold resource IDs of each item layout
             * row to prevent having to look them up each time data is
             * bound to a row.
             */
            private class ViewHolder {
                TextView displayname;
                QuickContactBadge quickcontact;
            }
            ...
            @Override
            public View newView(
                    Context context,
                    Cursor cursor,
                    ViewGroup viewGroup) {
                /* Inflates the item layout. Stores resource IDs in a
                 * in a ViewHolder class to prevent having to look
                 * them up each time bindView() is called.
                 */
                final View itemView =
                        mInflater.inflate(
                                R.layout.contact_list_layout,
                                viewGroup,
                                false
                        );
                final ViewHolder holder = new ViewHolder();
                holder.displayname =
                        (TextView) view.findViewById(R.id.displayname);
                holder.quickcontact =
                        (QuickContactBadge)
                                view.findViewById(R.id.quickcontact);
                view.setTag(holder);
                return view;
            }
            ...
            @Override
            public void bindView(
                    View view,
                    Context context,
                    Cursor cursor) {
                final ViewHolder holder = (ViewHolder) view.getTag();
                final String photoData =
                        cursor.getString(photoDataIndex);
                final String displayName =
                        cursor.getString(displayNameIndex);
                ...
                // Sets the display name in the layout
                holder.displayname = cursor.getString(displayNameIndex);
                ...
                /*
                 * Generates a contact URI for the QuickContactBadge.
                 */
                final Uri contactUri = Contacts.getLookupUri(
                        cursor.getLong(idIndex),
                        cursor.getString(lookupKeyIndex));
                holder.quickcontact.assignContactUri(contactUri);
                String photoData = cursor.getString(photoDataIndex);
                /*
                 * Decodes the thumbnail file to a Bitmap.
                 * The method loadContactPhotoThumbnail() is defined
                 * in the section "Set the Contact URI and Thumbnail"
                 */
                Bitmap thumbnailBitmap =
                        loadContactPhotoThumbnail(photoData);
                /*
                 * Sets the image in the QuickContactBadge
                 * QuickContactBadge inherits from ImageView
                 */
                holder.quickcontact.setImageBitmap(thumbnailBitmap);
        }
    

変数をセットアップする

コード内で、必要な列を格納する Cursor 代替表記を含め、各種変数をセットアップします。

注: 下記のコード スニペットは、連絡先 URI とサムネイルを設定するで定義した loadContactPhotoThumbnail() メソッドを使用しています。

たとえば、次のようになります。

Kotlin

    /*
     * Defines a projection based on platform version. This ensures
     * that you retrieve the correct columns.
     */
    private val PROJECTION: Array<out String> = arrayOf(
            ContactsContract.Contacts._ID,
            ContactsContract.Contacts.LOOKUP_KEY,
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
            } else {
                ContactsContract.Contacts.DISPLAY_NAME
            },
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                ContactsContract.Contacts.PHOTO_FILE_ID
            } else {
                /*
                 * Although it's not necessary to include the
                 * column twice, this keeps the number of
                 * columns the same regardless of version
                 */
                ContactsContract.Contacts._ID
            }
    )
    ...
    class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> {
        ...
        // Defines a ListView
        private val listView: ListView? = null
        // Defines a ContactsAdapter
        private val adapter: ContactsAdapter? = null
        ...
        // Defines a Cursor to contain the retrieved data
        private val cursor: Cursor? = null
        /*
         * As a shortcut, defines constants for the
         * column indexes in the Cursor. The index is
         * 0-based and always matches the column order
         * in the projection.
         */
        // Column index of the _ID column
        private val idIndex = 0
        // Column index of the LOOKUP_KEY column
        private val lookupKeyIndex = 1
        // Column index of the display name column
        private val displayNameIndex = 3
        /*
         * Column index of the photo data column.
         * It's PHOTO_THUMBNAIL_URI for Honeycomb and later,
         * and _ID for previous versions.
         */
        private val photoDataIndex: Int =
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) 3 else 0
        ...
    

Java

    public class ContactsFragment extends Fragment implements
            LoaderManager.LoaderCallbacks<Cursor> {
    ...
        // Defines a ListView
        private ListView listView;
        // Defines a ContactsAdapter
        private ContactsAdapter adapter;
        ...
        // Defines a Cursor to contain the retrieved data
        private Cursor cursor;
        /*
         * Defines a projection based on platform version. This ensures
         * that you retrieve the correct columns.
         */
        private static final String[] PROJECTION =
                {
                    ContactsContract.Contacts._ID,
                    ContactsContract.Contacts.LOOKUP_KEY,
                    (Build.VERSION.SDK_INT >=
                     Build.VERSION_CODES.HONEYCOMB) ?
                            ContactsContract.Contacts.DISPLAY_NAME_PRIMARY :
                            ContactsContract.Contacts.DISPLAY_NAME
                    (Build.VERSION.SDK_INT >=
                     Build.VERSION_CODES.HONEYCOMB) ?
                            ContactsContract.Contacts.PHOTO_FILE_ID :
                            /*
                             * Although it's not necessary to include the
                             * column twice, this keeps the number of
                             * columns the same regardless of version
                             */
                            ContactsContract.Contacts._ID
                };
        /*
         * As a shortcut, defines constants for the
         * column indexes in the Cursor. The index is
         * 0-based and always matches the column order
         * in the projection.
         */
        // Column index of the _ID column
        private int idIndex = 0;
        // Column index of the LOOKUP_KEY column
        private int lookupKeyIndex = 1;
        // Column index of the display name column
        private int displayNameIndex = 3;
        /*
         * Column index of the photo data column.
         * It's PHOTO_THUMBNAIL_URI for Honeycomb and later,
         * and _ID for previous versions.
         */
        private int photoDataIndex =
                Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
                3 :
                0;
        ...
    

ListView をセットアップする

Fragment.onCreate() 内で、カスタム カーソル アダプターをインスタンス化して、ListView のハンドルを取得します。

Kotlin

        override fun onCreateView(
                inflater: LayoutInflater,
                container: ViewGroup?,
                savedInstanceState: Bundle?
        ): View? {
            return inflater.inflate(...).let { view ->
                ...
                /*
                 * Gets a handle to the ListView in the file
                 * contact_list_layout.xml
                 */
                listView = view.findViewById<ListView>(R.id.contact_list)
                mAdapter?.also {
                    listView?.adapter = it
                }
                ...
            }
        }
        ...
    

Java

        @Override
        public View onCreateView(LayoutInflater inflater,
                ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(...)
            ...
            /*
             * Gets a handle to the ListView in the file
             * contact_list_layout.xml
             */
            listView = (ListView) view.findViewById(R.id.contact_list_view);
            if (listView != null && adapter != null) {
                listView.setAdapter(adapter);
            }
            ...
        }
        ...
    

onViewCreated() 内で、ContactsAdapterListView にバインドします。

Kotlin

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        /*
         * Instantiates the subclass of
         * CursorAdapter
         */
        mAdapter = activity?.let {
            ContactsAdapter(it).also { adapter ->
                // Sets up the adapter for the ListView
                listView?.adapter = adapter
            }
        }
    }
    

Java

    @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            ...
            /*
             * Instantiates the subclass of
             * CursorAdapter
             */
            mAdapter = new ContactsAdapter(getActivity());
            // Sets up the adapter for the ListView
            if (listView != null && mAdapter != null) {
                listView.setAdapter(mAdapter);
            }
            ...
        }
        ...
    

連絡先データを格納する Cursor に戻ったら、通常は onLoadFinished() 内で、swapCursor() を呼び出して、Cursor データを ListView に移動します。これにより、連絡先リストの各エントリに対して QuickContactBadge が表示されるようになります。

Kotlin

    override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) {
        // When the loader has completed, swap the cursor into the adapter.
        mAdapter?.swapCursor(cursor)
    }
    

Java

    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
            // When the loader has completed, swap the cursor into the adapter.
            mAdapter.swapCursor(cursor);
        }
    

CursorListViewCursorAdapter(またはサブクラス)にバインドし、CursorLoader を使用して Cursor をロードする場合は、必ず、onLoaderReset() 実装内にある Cursor への参照を削除してください。たとえば、次のようになります。

Kotlin

        override fun onLoaderReset(loader: Loader<Cursor>) {
            // Removes remaining reference to the previous Cursor
            adapter?.swapCursor(null)
        }
    

Java

        @Override
        public void onLoaderReset(Loader<Cursor> loader) {
            // Removes remaining reference to the previous Cursor
            adapter.swapCursor(null);
        }