顯示快速聯絡標記

本頁面說明如何將 QuickContactBadge 新增至 UI,以及如何將資料繫結至該 UI。QuickContactBadge 是最初顯示為縮圖圖片的小工具。雖然您可以使用任何 Bitmap 做為縮圖圖片,但通常會使用從聯絡人相片縮圖圖片解碼的 Bitmap

小型圖片就是控制項。當使用者輕觸圖片時,QuickContactBadge 會展開為包含以下內容的對話方塊:

大型圖片
與聯絡人相關聯的大型圖片,如果沒有圖片,則會顯示預留位置圖示。
應用程式圖示
每個內建應用程式可處理詳細資料資料的應用程式圖示。舉例來說,如果聯絡人的詳細資料包含一或多個電子郵件地址,系統就會顯示電子郵件圖示。使用者輕觸圖示時,系統會顯示所有聯絡人的電子郵件地址。當使用者輕觸其中一個地址時,電子郵件應用程式會顯示一則畫面,讓使用者撰寫要傳送給所選電子郵件地址的郵件。

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 cursor: 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
    ...
    cursor?.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)
        )
        binding.badge.assignContactUri(contactUri)
    }

Java

    // The Cursor that contains contact rows
    Cursor cursor;
    // 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;
    ...
    /*
     * 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 =
            Contacts.getLookupUri(
                cursor.getLong(idColumn),
                cursor.getString(lookupKeyColumn)
            );
    binding.badge.assignContactUri(contactUri);

使用者輕觸 QuickContactBadge 圖示時,對話方塊中會顯示聯絡人的詳細資料。

設定相片縮圖

QuickContactBadge 設定聯絡人 URI 不會自動載入聯絡人的縮圖相片。如要載入相片,請從聯絡人的 Cursor 列取得相片的 URI,然後使用該 URI 開啟包含已壓縮縮圖相片的檔案,並將檔案讀取至 Bitmap

注意:PHOTO_THUMBNAIL_URI 欄不適用於 3.0 之前的平台版本。對於這些版本,您必須從 Contacts.Photo 子表擷取 URI。

首先,請設定變數,以便存取包含 Contacts._IDContacts.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
    ...
    cursor?.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 ->
                // Decodes the photo file and returns 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();
        // Decodes the photo file and returns 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.
             */
            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.
     */
    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

如要將 CursorAdapter 繫結至包含 QuickContactBadgeListView,請定義可擴充 CursorAdapter 的自訂轉接器。您可以先在 Cursor 中處理資料,再將資料繫結至 QuickContactBadge。這個方法還可讓您將多個 Cursor 欄繫結至 QuickContactBadge。在一般的 CursorAdapter 中,這兩種作業都不可能。

您定義的 CursorAdapter 子類別必須覆寫下列方法:

CursorAdapter.newView()
以新 View 物件將項目版面配置保留在內。在這個方法的覆寫值中,將子項 View 物件 (包括子項 QuickContactBadge) 的句柄儲存起來。採用這種做法,您就不必在每次將新版面配置加載時,取得子項 View 物件的句柄。

您必須覆寫這個方法,才能取得個別子項 View 物件的處理常式。這項技巧可讓您在 CursorAdapter.bindView() 中控管綁定。

CursorAdapter.bindView()
將資料從目前的 Cursor 列移至項目版面配置的子項 View 物件。您必須覆寫這個方法,才能將聯絡人的 URI 和縮圖綁定至 QuickContactBadge。預設實作方式只允許資料欄與 View 之間的一對一對應。

以下程式碼片段包含 CursorAdapter 的自訂子類別範例:

定義自訂清單 Adapter

定義 CursorAdapter 的子類別,包括其建構函式,並覆寫 newView()bindView()

Kotlin

    /**
     * Defines a class that holds 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 view references
             * in a ViewHolder class to prevent having to look
             * them up each time bindView() is called.
             */
            return ContactListLayoutBinding.inflate(inflater,
                    viewGroup,
                    false).also { binding ->
                view.tag = ViewHolder().apply {
                    displayname = binding.displayname
                    quickcontact = binding.quickcontact
                }
            }.root
        }
        ...
        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 inflater;
        ...
        public ContactsAdapter(Context context) {
            super(context, null, 0);

            /*
             * Gets an inflater that can instantiate
             * the ListView layout from the file
             */
            inflater = LayoutInflater.from(context);
            ...
        }
        ...
        /**
         * Defines a class that holds 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 view references
             * in a ViewHolder class to prevent having to look
             * them up each time bindView() is called.
             */
            final ContactListLayoutBinding binding =
            ContactListLayoutBinding.inflate(inflater, 
                viewGroup,
                false);
            final ViewHolder holder = new ViewHolder();
            holder.displayname =
                    binding.displayName;
            holder.quickcontact =
                    binding.quickContact;
            view.setTag(holder);
            return binding.root;
        }
        ...
        @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 FragmentListViewBinding.inflate(...).let { binding ->
            ...
            /*
             * Gets a handle to the ListView in the file
             * contact_list_layout.xml
             */
            listView = binding.contactList
            mAdapter?.also {
                listView?.adapter = it
            }
            ...
        }.root
    }
    ...

Java

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

onViewCreated() 中,將 ContactsAdapter 繫結至 ListView

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

使用 CursorAdapter (或子類別) 將 Cursor 繫結至 ListView 並使用 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);
    }