빠른 주소록 배지 표시

이 과정에서는 UI에 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)
        }
    

자바

        // 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를 검색해야 합니다.

먼저 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)
        }
    

자바

        // 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) {
                }
            }
        }
    

자바

        /**
         * 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)
            }
        }
    

자바

        ...
        /*
         * 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);
    

ListView에 QuickContactBadge 추가

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 설정

CursorAdapterQuickContactBadge가 포함된 ListView에 바인딩하려면 CursorAdapter를 확장하는 맞춤 어댑터를 정의합니다. 이렇게 하면 QuickContactBadge에 바인딩하기 전에 Cursor에 있는 데이터를 처리할 수 있습니다. 또한 QuickContactBadge에 여러 개의 Cursor 열을 바인딩할 수도 있습니다. 두 가지 모두 일반적인 CursorAdapter에서는 할 수 없는 작업입니다.

정의한 CursorAdapter의 서브클래스는 다음 메서드를 재정의해야 합니다.

CursorAdapter.newView()
항목 레이아웃을 포함하기 위해 새로운 View 개체를 확장합니다. 이 메서드를 재정의할 때 하위 QuickContactBadge를 포함한 레이아웃의 하위 View 개체에 핸들을 저장합니다. 이 방법을 사용하면 새로운 레이아웃을 확장할 때마다 하위 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)
                            }
                        }
                    }
                }

            }
        }
    

자바

        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
        ...
    

자바

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

자바

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

onActivityCreated()에서 ContactsAdapterListView에 바인딩합니다.

Kotlin

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

자바

    @Override
        public void onActivityCreated(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)
    }
    

자바

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

CursorCursorAdapter(또는 서브클래스)가 포함된 ListView에 바인딩하고 CursorLoader를 사용하여 Cursor를 로드할 경우 항상 onLoaderReset() 구현에서 Cursor에 관한 참조를 삭제하시기 바랍니다. 예:

Kotlin

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

자바

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