显示快速联系标志

本课介绍了如何将 QuickContactBadge 添加到您的界面以及如何将数据与其绑定。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 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,使用 URI 打开包含经过压缩的照片缩略图的文件,然后将该文件读入 Bitmap

注意:3.0 之前的平台版本中没有 PHOTO_THUMBNAIL_URI 列。对于这些版本,您必须从 Contacts.Photo 子表检索 URI。

首先,设置变量以访问 Cursor,如前所述,其中包含 Contacts._IDContacts.LOOKUP_KEY 列:

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

如需将 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 的自定义子类:

定义自定义列表适配器

定义 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 映射。

注意:以下代码段使用方法 loadContactPhotoThumbnail(),该方法是在设置联系人 URI 和缩略图部分中定义的

例如:

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() 中,将 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);
        }
    

当您将CursorListViewCursorAdapter(或子类)绑定,并使用CursorLoader加载Cursor时,始终清除对Cursor的引用在实现onLoaderReset()中。 例如:

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