หน้านี้จะแสดงวิธีเพิ่ม QuickContactBadge
ลงใน 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 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
รายละเอียดของรายชื่อติดต่อจะปรากฏในกล่องโต้ตอบ
ตั้งค่าภาพปก
การตั้งค่า URI ของรายชื่อติดต่อสำหรับ QuickContactBadge
จะไม่โหลดรูปภาพขนาดย่อของผู้ติดต่อโดยอัตโนมัติ หากต้องการโหลดรูปภาพ ให้รับ URI ของรูปภาพจากแถว Cursor
ของรายชื่อติดต่อ ใช้ URI ดังกล่าวเพื่อเปิดไฟล์ที่มีรูปภาพขนาดย่อที่บีบอัด และอ่านไฟล์ลงใน Bitmap
หมายเหตุ: คอลัมน์ PHOTO_THUMBNAIL_URI
ไม่พร้อมใช้งานในแพลตฟอร์มเวอร์ชันก่อน 3.0 สำหรับเวอร์ชันดังกล่าว คุณต้องดึงข้อมูล URI จากตารางย่อย Contacts.Photo
ก่อนอื่น ให้ตั้งค่าตัวแปรเพื่อเข้าถึง Cursor
ที่มีคอลัมน์ Contacts._ID
และ Contacts.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 ... 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
กับ ListView
ที่มี QuickContactBadge
ให้กำหนดอะแดปเตอร์ที่กำหนดเองซึ่งขยาย CursorAdapter
วิธีนี้ช่วยให้คุณประมวลผลข้อมูลใน Cursor
ได้ก่อนที่จะเชื่อมโยงกับ QuickContactBadge
แนวทางนี้ยังช่วยให้คุณเชื่อมโยงCursor
หลายคอลัมน์กับQuickContactBadge
ได้ด้วย การดำเนินการเหล่านี้ไม่สามารถทำได้ใน CursorAdapter
ปกติ
คลาสย่อยของ CursorAdapter
ที่คุณกำหนดต้องลบล้างเมธอดต่อไปนี้
CursorAdapter.newView()
-
ขยายออบเจ็กต์
View
ใหม่เพื่อเก็บเลย์เอาต์รายการ ในการลบล้างของเมธอดนี้ ให้จัดเก็บแฮนเดิลของออบเจ็กต์View
ย่อยของเลย์เอาต์ รวมถึงออบเจ็กต์ย่อยQuickContactBadge
การใช้แนวทางนี้จะช่วยให้คุณไม่ต้องรับแฮนเดิลสำหรับออบเจ็กต์View
ย่อยทุกครั้งที่ขยายเลย์เอาต์ใหม่คุณต้องลบล้างเมธอดนี้เพื่อให้รับแฮนเดิลสำหรับออบเจ็กต์
View
ย่อยแต่ละรายการได้ เทคนิคนี้ช่วยให้คุณควบคุมการเชื่อมโยงได้ในCursorAdapter.bindView()
CursorAdapter.bindView()
-
ย้ายข้อมูลจากแถว
Cursor
ปัจจุบันไปยังออบเจ็กต์ย่อยView
ของเลย์เอาต์รายการ คุณต้องลบล้างเมธอดนี้เพื่อให้สามารถเชื่อมโยงทั้ง URI ของรายชื่อติดต่อและภาพขนาดย่อกับQuickContactBadge
ได้ การใช้งานเริ่มต้นอนุญาตให้มีการแมปแบบ 1 ต่อ 1 ระหว่างคอลัมน์กับView
เท่านั้น
ข้อมูลโค้ดต่อไปนี้มีตัวอย่างคลาสย่อยที่กําหนดเองของ CursorAdapter
กำหนดอะแดปเตอร์รายการที่กำหนดเอง
กำหนดคลาสย่อยของ 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
ที่มีคอลัมน์ที่จำเป็น ดังที่แสดงในตัวอย่างต่อไปนี้
หมายเหตุ: ข้อมูลโค้ดต่อไปนี้ใช้เมธอด 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 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); }
เมื่อคุณเชื่อมโยง Cursor
กับ ListView
ที่มี CursorAdapter
(หรือคลาสย่อย) และใช้ 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); }