บทเรียนนี้จะแสดงวิธีดึงข้อมูลรายชื่อติดต่อที่มีข้อมูลตรงกับสตริงการค้นหาทั้งหมดหรือบางส่วนโดยใช้เทคนิคต่อไปนี้
- จับคู่ชื่อผู้ติดต่อ
- เรียกดูรายชื่อรายชื่อติดต่อโดยการจับคู่สตริงการค้นหากับรายชื่อติดต่อทั้งหมดหรือบางส่วน ข้อมูลชื่อ ผู้ให้บริการรายชื่อติดต่ออนุญาตให้ใช้ชื่อเดียวกันได้หลายรายการ ดังนั้นเทคนิคนี้จึงแสดงรายการที่ตรงกันได้
- จับคู่ข้อมูลบางประเภท เช่น หมายเลขโทรศัพท์
- ดึงรายชื่อผู้ติดต่อโดยการจับคู่สตริงการค้นหากับประเภทรายละเอียดที่ต้องการ ข้อมูล เช่น อีเมล ตัวอย่างเช่น เทคนิคนี้ช่วยให้คุณแสดงรายการ รายชื่อติดต่อที่มีที่อยู่อีเมลตรงกับสตริงการค้นหา
- จับคู่ข้อมูลประเภทใดก็ได้
- ดึงข้อมูลรายชื่อติดต่อโดยการจับคู่สตริงการค้นหากับข้อมูลแบบละเอียดประเภทใดก็ได้ ซึ่งรวมถึงชื่อ หมายเลขโทรศัพท์ ที่อยู่ อีเมล และอื่นๆ ตัวอย่างเช่น เทคนิคนี้ช่วยให้คุณยอมรับข้อมูลประเภทใดก็ได้สำหรับสตริงการค้นหา จากนั้นแสดงรายชื่อรายชื่อติดต่อที่มีข้อมูลที่ตรงกับสตริง
หมายเหตุ: ตัวอย่างทั้งหมดในบทเรียนนี้ใช้
CursorLoader
เพื่อดึงข้อมูลจากรายชื่อติดต่อ
ผู้ให้บริการ CursorLoader
จะเรียกใช้การค้นหาในเธรดที่แยกจากเธรด UI วิธีนี้ช่วยให้มั่นใจว่าการค้นหาจะไม่ทำให้ UI ช้าลง
เวลาในการตอบสนองและทำให้ผู้ใช้ได้รับประสบการณ์ที่ไม่ดี ดูข้อมูลเพิ่มเติมได้ที่ชั้นเรียนการฝึกอบรม Android การโหลดข้อมูลในเบื้องหลัง
ขอสิทธิ์อ่านผู้ให้บริการ
หากต้องการค้นหาประเภทใดก็ตามของผู้ให้บริการรายชื่อติดต่อ แอปของคุณต้องมีสิทธิ์ READ_CONTACTS
หากต้องการขอสิทธิ์นี้ ให้เพิ่มองค์ประกอบ <uses-permission>
นี้ลงในไฟล์ Manifest เป็นองค์ประกอบย่อยของ <manifest>
<uses-permission android:name="android.permission.READ_CONTACTS" />
จับคู่รายชื่อติดต่อตามชื่อและแสดงผลลัพธ์
เทคนิคนี้จะพยายามจับคู่สตริงการค้นหากับชื่อของรายชื่อติดต่อหรือรายชื่อติดต่อใน
ติดต่อตาราง ContactsContract.Contacts
ของผู้ให้บริการ โดยปกติแล้ว คุณจะต้องแสดงผลลัพธ์ใน ListView
เพื่อให้ผู้ใช้เลือกรายชื่อติดต่อที่ตรงกันได้
กําหนดเลย์เอาต์ ListView และรายการ
หากต้องการแสดงผลการค้นหาใน ListView
คุณต้องมีไฟล์เลย์เอาต์หลัก
ที่กำหนด UI ทั้งหมด รวมถึง ListView
และการจัดวางรายการ
ที่กำหนด ListView
บรรทัดเดียว ตัวอย่างเช่น คุณสามารถสร้าง
ไฟล์เลย์เอาต์หลัก res/layout/contacts_list_view.xml
ด้วย
XML ต่อไปนี้
<?xml version="1.0" encoding="utf-8"?> <ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent"/>
XML นี้ใช้วิดเจ็ต ListView
ของ Android ในตัว
android:id/list
กำหนดไฟล์เลย์เอาต์สินค้า contacts_list_item.xml
ด้วย XML ต่อไปนี้
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true"/>
XML นี้ใช้วิดเจ็ต TextView
ของ Android ในตัว
android:text1
หมายเหตุ: บทเรียนนี้ไม่ได้อธิบาย UI สำหรับการรับสตริงค้นหาจาก เพราะคุณอาจต้องได้รับสตริงทางอ้อม เช่น คุณสามารถให้ผู้ใช้ ตัวเลือกสำหรับค้นหารายชื่อติดต่อที่ชื่อตรงกับสตริงในข้อความขาเข้า
ไฟล์เลย์เอาต์ 2 ไฟล์ที่คุณเขียนจะกำหนดอินเทอร์เฟซผู้ใช้ที่แสดง ListView
ขั้นตอนถัดไปคือการเขียนโค้ดที่ใช้ UI นี้เพื่อแสดงรายชื่อติดต่อ
กำหนด Fregment ที่แสดงรายการรายชื่อติดต่อ
หากต้องการแสดงรายชื่อรายชื่อติดต่อ ให้เริ่มด้วยการกำหนด Fragment
โหลดโดย Activity
การใช้
Fragment
เป็นเทคนิคที่ยืดหยุ่นกว่าเนื่องจากคุณใช้
Fragment
1 ชิ้นเพื่อแสดงรายการและอีก 1 วินาที
Fragment
เพื่อแสดงรายละเอียดของรายชื่อติดต่อที่ผู้ใช้
เลือกจากรายการ เมื่อใช้แนวทางนี้ คุณสามารถรวมเทคนิคใดเทคนิคหนึ่งจากบทเรียนนี้เข้ากับเทคนิคจากบทเรียนดึงข้อมูลรายละเอียดสำหรับรายชื่อติดต่อ
หากต้องการดูวิธีใช้ออบเจ็กต์ Fragment
อย่างน้อย 1 รายการจาก Activity
โปรดอ่านชั้นเรียนการฝึกอบรม สร้าง UI แบบไดนามิกด้วย Framgnet
เฟรมเวิร์ก Android มีคลาสสัญญาที่เรียกว่า ContactsContract
ซึ่งจะกำหนดค่าคงที่และเมธอดที่มีประโยชน์สำหรับการเข้าถึงผู้ให้บริการเพื่อช่วยให้คุณเขียนการค้นหากับ Contacts Provider ได้ เมื่อใช้คลาสนี้ คุณไม่จําเป็นต้องกําหนดค่าคงที่ของคุณเองสําหรับ URI ของเนื้อหา ชื่อตาราง หรือคอลัมน์ หากต้องการใช้คลาสนี้ ให้ใส่คำสั่งต่อไปนี้
Kotlin
import android.provider.ContactsContract
Java
import android.provider.ContactsContract;
เนื่องจากโค้ดใช้ CursorLoader
เพื่อดึงข้อมูลจากผู้ให้บริการ คุณต้องระบุว่าโค้ดใช้อินเทอร์เฟซโปรแกรมโหลด LoaderManager.LoaderCallbacks
นอกจากนี้ ให้ใช้อินเทอร์เฟซอะแดปเตอร์ AdapterView.OnItemClickListener
เพื่อช่วยตรวจหารายชื่อติดต่อที่ผู้ใช้เลือกจากรายการผลการค้นหา เช่น
Kotlin
... import android.support.v4.app.Fragment import android.support.v4.app.LoaderManager import android.widget.AdapterView ... class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener {
Java
... import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.widget.AdapterView; ... public class ContactsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener {
กําหนดตัวแปรส่วนกลาง
กำหนดตัวแปรส่วนกลางที่ใช้ในส่วนอื่นๆ ของโค้ด
Kotlin
... /* * Defines an array that contains column names to move from * the Cursor to the ListView. */ @SuppressLint("InlinedApi") private val FROM_COLUMNS: Array<String> = arrayOf( if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)) { ContactsContract.Contacts.DISPLAY_NAME_PRIMARY } else { ContactsContract.Contacts.DISPLAY_NAME } ) /* * Defines an array that contains resource ids for the layout views * that get the Cursor column contents. The id is pre-defined in * the Android framework, so it is prefaced with "android.R.id" */ private val TO_IDS: IntArray = intArrayOf(android.R.id.text1) ... class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener { ... // Define global mutable variables // Define a ListView object lateinit var contactsList: ListView // Define variables for the contact the user selects // The contact's _ID value var contactId: Long = 0 // The contact's LOOKUP_KEY var contactKey: String? = null // A content URI for the selected contact var contactUri: Uri? = null // An adapter that binds the result Cursor to the ListView private val cursorAdapter: SimpleCursorAdapter? = null
Java
... /* * Defines an array that contains column names to move from * the Cursor to the ListView. */ @SuppressLint("InlinedApi") private final static String[] FROM_COLUMNS = { Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME }; /* * Defines an array that contains resource ids for the layout views * that get the Cursor column contents. The id is pre-defined in * the Android framework, so it is prefaced with "android.R.id" */ private final static int[] TO_IDS = { android.R.id.text1 }; // Define global mutable variables // Define a ListView object ListView contactsList; // Define variables for the contact the user selects // The contact's _ID value long contactId; // The contact's LOOKUP_KEY String contactKey; // A content URI for the selected contact Uri contactUri; // An adapter that binds the result Cursor to the ListView private SimpleCursorAdapter cursorAdapter; ...
หมายเหตุ: เนื่องจากContacts.DISPLAY_NAME_PRIMARY
ต้องใช้ Android 3.0 (API เวอร์ชัน 11) ขึ้นไป การตั้งค่า minSdkVersion
ของแอปเป็น 10 หรือต่ำกว่าจะทำให้เกิดคำเตือน Android Lint ใน Android Studio หากต้องการปิดคำเตือนนี้ ให้เพิ่มคำอธิบายประกอบ
@SuppressLint("InlinedApi")
ก่อนคำจำกัดความของ FROM_COLUMNS
เริ่มต้น Fragment
เริ่มต้น Fragment
เพิ่มคอนสตรัคเตอร์แบบว่างและแบบสาธารณะที่ระบบ Android ต้องการ และขยาย UI ของออบเจ็กต์ Fragment
ในเมธอดการเรียกกลับ onCreateView()
เช่น
Kotlin
// A UI Fragment must inflate its View override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the fragment layout return inflater.inflate(R.layout.contact_list_fragment, container, false) }
Java
// Empty public constructor, required by the system public ContactsFragment() {} // A UI Fragment must inflate its View @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the fragment layout return inflater.inflate(R.layout.contact_list_fragment, container, false); }
ตั้งค่า CursorAdapter สำหรับ ListView
ตั้งค่า SimpleCursorAdapter
ที่เชื่อมโยงผลลัพธ์ของ
ให้ค้นหา ListView
วิธีรับออบเจ็กต์ ListView
ที่แสดงรายชื่อติดต่อ คุณต้องโทรหา Activity.findViewById()
โดยใช้กิจกรรมของผู้ปกครองของ
Fragment
ใช้ Context
ของ
กิจกรรมของผู้ปกครองเมื่อโทรหา setAdapter()
เช่น
Kotlin
override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) ... // Gets the ListView from the View list of the parent activity activity?.also { contactsList = it.findViewById<ListView>(R.id.contact_list_view) // Gets a CursorAdapter cursorAdapter = SimpleCursorAdapter( it, R.layout.contact_list_item, null, FROM_COLUMNS, TO_IDS, 0 ) // Sets the adapter for the ListView contactsList.adapter = cursorAdapter } }
Java
public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ... // Gets the ListView from the View list of the parent activity contactsList = (ListView) getActivity().findViewById(R.layout.contact_list_view); // Gets a CursorAdapter cursorAdapter = new SimpleCursorAdapter( getActivity(), R.layout.contact_list_item, null, FROM_COLUMNS, TO_IDS, 0); // Sets the adapter for the ListView contactsList.setAdapter(cursorAdapter); }
ตั้งค่า Listener รายชื่อติดต่อที่เลือก
เมื่อแสดงผลการค้นหา คุณมักจะต้องอนุญาตให้ผู้ใช้เลือกรายชื่อติดต่อรายการเดียวเพื่อดำเนินการต่อ ตัวอย่างเช่น เมื่อผู้ใช้คลิกรายชื่อติดต่อ คุณสามารถแสดงที่อยู่ของรายชื่อติดต่อบนแผนที่ ในการเปิดใช้ฟีเจอร์นี้ ก่อนอื่นคุณต้องกำหนด
Fragment
เป็นผู้ฟังการคลิกด้วยการระบุว่าคลาส
ใช้ AdapterView.OnItemClickListener
ดังที่แสดงในส่วน
กำหนดส่วนย่อยที่แสดงรายชื่อติดต่อ
หากต้องการตั้งค่า Listener ต่อ ให้เชื่อมโยงกับ ListView
โดย
กำลังเรียกเมธอด setOnItemClickListener()
ใน onActivityCreated()
เช่น
Kotlin
fun onActivityCreated(savedInstanceState:Bundle) { ... // Set the item click listener to be the current fragment. contactsList.onItemClickListener = this ... }
Java
public void onActivityCreated(Bundle savedInstanceState) { ... // Set the item click listener to be the current fragment. contactsList.setOnItemClickListener(this); ... }
เนื่องจากคุณระบุว่า Fragment
ปัจจุบันคือ
OnItemClickListener
สำหรับ
ListView
ตอนนี้คุณต้องใช้วิธีการที่จำเป็นแล้ว
onItemClick()
ซึ่ง
จัดการกิจกรรมการคลิก โปรดดูรายละเอียดในส่วนถัดไป
กำหนดการฉายภาพ
กําหนดค่าคงที่ซึ่งมีคอลัมน์ที่คุณต้องการแสดงผลจากคําค้นหา แต่ละรายการใน
ListView
จะแสดงชื่อที่แสดงของรายชื่อติดต่อ
ซึ่งมีรูปแบบหลักของชื่อผู้ติดต่อ ใน Android 3.0 (API เวอร์ชัน 11) ขึ้นไป ชื่อของคอลัมน์นี้คือ Contacts.DISPLAY_NAME_PRIMARY
ส่วนในเวอร์ชันก่อนหน้าชื่อของคอลัมน์นี้คือ Contacts.DISPLAY_NAME
กระบวนการเชื่อมโยง SimpleCursorAdapter
ใช้คอลัมน์ Contacts._ID
ระบบจะใช้ Contacts._ID
และ
LOOKUP_KEY
ร่วมกันเพื่อสร้าง URI ของเนื้อหาสําหรับรายชื่อติดต่อที่ผู้ใช้เลือก
Kotlin
... @SuppressLint("InlinedApi") 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 )
Java
... @SuppressLint("InlinedApi") private static final String[] PROJECTION = { Contacts._ID, Contacts.LOOKUP_KEY, Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME };
กำหนดค่าคงที่สำหรับดัชนีคอลัมน์เคอร์เซอร์
หากต้องการข้อมูลจากคอลัมน์เดียวใน Cursor
คุณต้องมีดัชนีของคอลัมน์ภายใน Cursor
คุณสามารถกำหนดค่าคงที่
สำหรับดัชนีของคอลัมน์ Cursor
เนื่องจากดัชนี
เหมือนกับลำดับของชื่อคอลัมน์ในการฉายภาพ เช่น
Kotlin
// The column index for the _ID column private const val CONTACT_ID_INDEX: Int = 0 // The column index for the CONTACT_KEY column private const val CONTACT_KEY_INDEX: Int = 1
Java
// The column index for the _ID column private static final int CONTACT_ID_INDEX = 0; // The column index for the CONTACT_KEY column private static final int CONTACT_KEY_INDEX = 1;
ระบุเกณฑ์การเลือก
หากต้องการระบุข้อมูลที่ต้องการ ให้สร้างชุดค่าผสมของนิพจน์ข้อความและตัวแปร ซึ่งบอกผู้ให้บริการเกี่ยวกับคอลัมน์ข้อมูลที่จะค้นหาและค่าที่จะค้นหา
สําหรับนิพจน์ข้อความ ให้กําหนดค่าคงที่ซึ่งแสดงรายการคอลัมน์การค้นหา แม้ว่านิพจน์นี้จะมีค่าด้วย แต่แนวทางปฏิบัติแนะนำคือให้แสดงค่าด้วยตัวยึดตําแหน่ง "?" ระหว่างการดึงข้อมูล ตัวยึดตำแหน่งจะถูกแทนที่ด้วยค่าจาก อาร์เรย์ การใช้ "?" เป็นตัวยึดตําแหน่งช่วยให้มั่นใจว่าระบบจะสร้างข้อกําหนดการค้นหาโดยการเชื่อมโยง ไม่ใช่โดยการคอมไพล์ SQL แนวทางปฏิบัตินี้ช่วยลดโอกาสที่จะมีการแทรก SQL ที่เป็นอันตราย เช่น
Kotlin
// Defines the text expression @SuppressLint("InlinedApi") private val SELECTION: String = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) "${ContactsContract.Contacts.DISPLAY_NAME_PRIMARY} LIKE ?" else "${ContactsContract.Contacts.DISPLAY_NAME} LIKE ?" ... // Defines a variable for the search string private val searchString: String = ... // Defines the array to hold values that replace the ? private val selectionArgs = arrayOf<String>(searchString)
Java
// Defines the text expression @SuppressLint("InlinedApi") private static final String SELECTION = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?" : Contacts.DISPLAY_NAME + " LIKE ?"; // Defines a variable for the search string private String searchString; // Defines the array to hold values that replace the ? private String[] selectionArgs = { searchString };
กำหนดเมธอด onItemClick()
ในส่วนก่อนหน้า คุณตั้งค่า Listener การคลิกรายการสำหรับ ListView
ตอนนี้ให้ใช้การดำเนินการสําหรับ Listener โดยกําหนดเมธอดดังนี้
AdapterView.OnItemClickListener.onItemClick()
Kotlin
override fun onItemClick(parent: AdapterView<*>, view: View?, position: Int, id: Long) { // Get the Cursor val cursor: Cursor? = (parent.adapter as? CursorAdapter)?.cursor?.apply { // Move to the selected contact moveToPosition(position) // Get the _ID value contactId = getLong(CONTACT_ID_INDEX) // Get the selected LOOKUP KEY contactKey = getString(CONTACT_KEY_INDEX) // Create the contact's content Uri contactUri = ContactsContract.Contacts.getLookupUri(contactId, mContactKey) /* * You can use contactUri as the content URI for retrieving * the details for a contact. */ } }
Java
@Override public void onItemClick( AdapterView<?> parent, View item, int position, long rowID) { // Get the Cursor Cursor cursor = parent.getAdapter().getCursor(); // Move to the selected contact cursor.moveToPosition(position); // Get the _ID value contactId = cursor.getLong(CONTACT_ID_INDEX); // Get the selected LOOKUP KEY contactKey = cursor.getString(CONTACT_KEY_INDEX); // Create the contact's content Uri contactUri = Contacts.getLookupUri(contactId, mContactKey); /* * You can use contactUri as the content URI for retrieving * the details for a contact. */ }
เริ่มต้นตัวโหลด
เนื่องจากคุณใช้ CursorLoader
เพื่อดึงข้อมูล
คุณต้องเริ่มต้นเทรดพื้นหลังและตัวแปรอื่นๆ ที่ควบคุมแบบอะซิงโครนัส
การดึงข้อมูล เริ่มต้นใน
onCreate()
เป็น
ที่แสดงในตัวอย่างต่อไปนี้
Kotlin
class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> { ... override fun onCreate(savedInstanceState: Bundle?) { // Always call the super method first super.onCreate(savedInstanceState) ... // Initializes the loader loaderManager.initLoader(0, null, this)
Java
public class ContactsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { ... // Called just before the Fragment displays its UI @Override public void onCreate(Bundle savedInstanceState) { // Always call the super method first super.onCreate(savedInstanceState); ... // Initializes the loader getLoaderManager().initLoader(0, null, this);
ใช้ onCreateLoader()
ใช้เมธอด
onCreateLoader()
,
ซึ่งจะเรียกโดยเฟรมเวิร์กตัวโหลดทันทีหลังจากที่คุณเรียก
initLoader()
ใน onCreateLoader()
ให้ตั้งค่ารูปแบบสตริงการค้นหา หากต้องการทำให้สตริงเป็นรูปแบบ ให้แทรก "%"
(เปอร์เซ็นต์) อักขระเพื่อแสดงลำดับของอักขระศูนย์ตัวขึ้นไป หรือ "_" (ขีดล่าง)
อักขระเพื่อแสดงอักขระตัวเดียว หรือทั้งสองตัว ตัวอย่างเช่น รูปแบบ "%Jefferson%"
จะตรงกับทั้ง "โทมัส เจฟเฟอร์สัน" และ "Jefferson Davis"
แสดงผล CursorLoader
ใหม่จากเมธอด สำหรับเนื้อหา
URI ให้ใช้ Contacts.CONTENT_URI
URI นี้ใช้อ้างอิงทั้งตาราง ดังที่ปรากฏในตัวอย่างต่อไปนี้
Kotlin
... override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> { /* * Makes search string into pattern and * stores it in the selection array */ selectionArgs[0] = "%$mSearchString%" // Starts the query return activity?.let { return CursorLoader( it, ContactsContract.Contacts.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ) } ?: throw IllegalStateException() }
Java
... @Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { /* * Makes search string into pattern and * stores it in the selection array */ selectionArgs[0] = "%" + searchString + "%"; // Starts the query return new CursorLoader( getActivity(), ContactsContract.Contacts.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ); }
ติดตั้งใช้งาน onLoadFinished() และ onLoaderreset()
ใช้เมธอด onLoadFinished()
การเรียกใช้เฟรมเวิร์กของตัวโหลด
onLoadFinished()
เมื่อผู้ให้บริการรายชื่อติดต่อแสดงผลการค้นหา ด้วยวิธีนี้ ให้ใส่
ผลลัพธ์ Cursor
ใน
SimpleCursorAdapter
ซึ่งจะอัปเดต ListView
ด้วยผลการค้นหาโดยอัตโนมัติ
Kotlin
override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) { // Put the result Cursor in the adapter for the ListView cursorAdapter?.swapCursor(cursor) }
Java
@Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { // Put the result Cursor in the adapter for the ListView cursorAdapter.swapCursor(cursor); }
เมธอด onLoaderReset()
จะถูกเรียกใช้เมื่อเฟรมเวิร์กของตัวโหลดตรวจพบว่า
ผลลัพธ์ Cursor
มีข้อมูลเก่า ลบการอ้างอิง SimpleCursorAdapter
ไปยัง Cursor
ที่มีอยู่ หากคุณไม่ทำเช่นนี้ เฟรมเวิร์กตัวโหลดจะไม่
รีไซเคิล Cursor
ซึ่งทำให้หน่วยความจำรั่วไหล เช่น
Kotlin
override fun onLoaderReset(loader: Loader<Cursor>) { // Delete the reference to the existing Cursor cursorAdapter?.swapCursor(null) }
Java
@Override public void onLoaderReset(Loader<Cursor> loader) { // Delete the reference to the existing Cursor cursorAdapter.swapCursor(null); }
ตอนนี้คุณมีข้อมูลสำคัญของแอปที่ตรงกับสตริงการค้นหากับชื่อผู้ติดต่อและการคืนสินค้าแล้ว
ผลลัพธ์เป็น ListView
ผู้ใช้คลิกชื่อรายชื่อติดต่อเพื่อเลือกได้
การดำเนินการนี้จะทริกเกอร์ Listener ซึ่งคุณสามารถทำงานกับข้อมูลของรายชื่อติดต่อเพิ่มเติมได้ เช่น คุณสามารถเรียกดูรายละเอียดของรายชื่อติดต่อ หากต้องการดูวิธีดำเนินการ ให้ไปที่บทเรียนถัดไป ซึ่งก็คือเรียกดูรายละเอียดสำหรับรายชื่อติดต่อ
หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับอินเทอร์เฟซผู้ใช้การค้นหา โปรดอ่านคู่มือ API สร้างอินเทอร์เฟซการค้นหา
ส่วนที่เหลือในบทนี้จะแสดงวิธีอื่นๆ ในการค้นหารายชื่อติดต่อในผู้ให้บริการรายชื่อติดต่อ
จับคู่รายชื่อติดต่อตามข้อมูลบางประเภท
เทคนิคนี้ช่วยให้คุณระบุประเภทข้อมูลที่ต้องการจับคู่ได้ การดึงข้อมูลตามชื่อเป็นตัวอย่างที่เฉพาะเจาะจงของการค้นหาประเภทนี้ แต่คุณยังดึงข้อมูลรายละเอียดประเภทใดก็ได้ที่เชื่อมโยงกับรายชื่อติดต่อ เช่น คุณสามารถเรียกข้อมูลรายชื่อติดต่อที่มีรหัสไปรษณีย์ที่เฉพาะเจาะจงได้ ในกรณีนี้ สตริงการค้นหาต้องตรงกับข้อมูลที่จัดเก็บไว้ในแถวรหัสไปรษณีย์
หากต้องการใช้การดึงข้อมูลประเภทนี้ ให้ติดตั้งใช้งานโค้ดต่อไปนี้ก่อนตามที่ระบุไว้ในส่วนก่อนหน้า
- ขอสิทธิ์อ่านผู้ให้บริการ
- กำหนดเลย์เอาต์ ListView และรายการ
- กำหนด Fregment ที่แสดงรายการรายชื่อติดต่อ
- กําหนดตัวแปรส่วนกลาง
- เริ่มต้น Fragment
- ตั้งค่า CursorAdapter สำหรับ ListView
- ตั้งค่า Listener ของรายชื่อติดต่อที่เลือก
-
ระบุค่าคงที่สำหรับดัชนีคอลัมน์เคอร์เซอร์
แม้ว่าคุณจะดึงข้อมูลจากตารางอื่น แต่ลำดับของคอลัมน์ใน การฉายภาพเหมือนกัน คุณจึงใช้ดัชนีเดียวกันสำหรับเคอร์เซอร์ได้
- กำหนดเมธอด onItemClick()
- เริ่มต้นตัวโหลด
- ใช้ onLoadFinished() และ onLoaderReset()
ขั้นตอนต่อไปนี้จะแสดงรหัสเพิ่มเติมที่คุณต้องจับคู่สตริงการค้นหา ข้อมูลรายละเอียดบางประเภทแล้วแสดงผล
เลือกประเภทข้อมูลและตาราง
หากต้องการค้นหาข้อมูลรายละเอียดประเภทใดประเภทหนึ่ง คุณต้องทราบค่าประเภท MIME ที่กําหนดเองสําหรับประเภทข้อมูลนั้น ข้อมูลแต่ละประเภทมีประเภท MIME ที่ไม่ซ้ำกัน
ค่าที่กำหนดโดย CONTENT_ITEM_TYPE
คงที่ในคลาสย่อยของ
ContactsContract.CommonDataKinds
ที่เชื่อมโยงกับประเภทข้อมูล
ซับคลาสจะมีชื่อที่ระบุประเภทข้อมูล เช่น ซับคลาสสําหรับข้อมูลอีเมลคือ ContactsContract.CommonDataKinds.Email
และประเภท MIME ที่กําหนดเองสําหรับข้อมูลอีเมลจะกําหนดโดยค่าคงที่ Email.CONTENT_ITEM_TYPE
ใช้ตาราง ContactsContract.Data
สำหรับการค้นหา ตารางนี้จะกำหนดหรือรับค่าคงที่ทั้งหมดที่จำเป็นสำหรับการแสดงผล คำสั่งการเลือก และลําดับการจัดเรียง
กำหนดการฉายภาพ
หากต้องการกําหนดโปรเจ็กชัน ให้เลือกคอลัมน์อย่างน้อย 1 คอลัมน์ที่กําหนดไว้ใน ContactsContract.Data
หรือคลาสที่รับค่ามา ผู้ให้บริการรายชื่อติดต่อจะทำการรวมข้อมูลโดยนัยระหว่าง ContactsContract.Data
กับตารางอื่นๆ ก่อนที่จะแสดงผลแถว เช่น
Kotlin
@SuppressLint("InlinedApi") private val PROJECTION: Array<out String> = arrayOf( /* * The detail data row ID. To make a ListView work, * this column is required. */ ContactsContract.Data._ID, // The primary display name if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) ContactsContract.Data.DISPLAY_NAME_PRIMARY else ContactsContract.Data.DISPLAY_NAME, // The contact's _ID, to construct a content URI ContactsContract.Data.CONTACT_ID, // The contact's LOOKUP_KEY, to construct a content URI ContactsContract.Data.LOOKUP_KEY )
Java
@SuppressLint("InlinedApi") private static final String[] PROJECTION = { /* * The detail data row ID. To make a ListView work, * this column is required. */ ContactsContract.Data._ID, // The primary display name Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? ContactsContract.Data.DISPLAY_NAME_PRIMARY : ContactsContract.Data.DISPLAY_NAME, // The contact's _ID, to construct a content URI ContactsContract.Data.CONTACT_ID, // The contact's LOOKUP_KEY, to construct a content URI ContactsContract.Data.LOOKUP_KEY // A permanent link to the contact };
กำหนดเกณฑ์การค้นหา
หากต้องการค้นหาสตริงภายในประเภทข้อมูลหนึ่งๆ ให้สร้างเงื่อนไขการเลือกจาก ดังต่อไปนี้
-
ชื่อของคอลัมน์ที่มีสตริงการค้นหา ชื่อนี้จะแตกต่างกันไปตามประเภทข้อมูล
คุณจึงต้องหาคลาสย่อยของ
ContactsContract.CommonDataKinds
ที่สอดคล้องกับประเภทข้อมูล แล้วเลือกชื่อคอลัมน์จากคลาสย่อยนั้น เช่น หากต้องการค้นหา ให้ใช้คอลัมน์Email.ADDRESS
- สตริงการค้นหาเอง ซึ่งแสดงเป็นอักขระ "?" ในคำสั่งการเลือก
-
ชื่อของคอลัมน์ที่มีค่าประเภท MIME ที่กำหนดเอง ชื่อนี้เสมอ
Data.MIMETYPE
-
ค่าประเภท MIME ที่กําหนดเองสําหรับประเภทข้อมูล ตามที่อธิบายไว้ก่อนหน้านี้ ค่านี้เป็นค่าคงที่
CONTENT_ITEM_TYPE
ในช่วง คลาสย่อยContactsContract.CommonDataKinds
ตัวอย่างเช่น MIME ค่าประเภทสำหรับข้อมูลอีเมลคือEmail.CONTENT_ITEM_TYPE
ใส่ค่าในเครื่องหมายคำพูดเดี่ยวโดยต่ออักขระ "'
" (เครื่องหมายคำพูดเดี่ยว) ไว้ที่จุดเริ่มต้นและจุดสิ้นสุดของค่าคงที่ ไม่เช่นนั้น ผู้ให้บริการจะตีความค่านั้นเป็นชื่อตัวแปรแทนที่จะเป็นค่าสตริง คุณไม่จำเป็นต้องใช้ตัวยึดตําแหน่งสำหรับค่านี้ เนื่องจากคุณใช้ค่าคงที่แทนค่าที่ผู้ใช้ระบุ
เช่น
Kotlin
/* * Constructs search criteria from the search string * and email MIME type */ private val SELECTION: String = /* * Searches for an email address * that matches the search string */ "${Email.ADDRESS} LIKE ? AND " + /* * Searches for a MIME type that matches * the value of the constant * Email.CONTENT_ITEM_TYPE. Note the * single quotes surrounding Email.CONTENT_ITEM_TYPE. */ "${ContactsContract.Data.MIMETYPE } = '${Email.CONTENT_ITEM_TYPE}'"
Java
/* * Constructs search criteria from the search string * and email MIME type */ private static final String SELECTION = /* * Searches for an email address * that matches the search string */ Email.ADDRESS + " LIKE ? " + "AND " + /* * Searches for a MIME type that matches * the value of the constant * Email.CONTENT_ITEM_TYPE. Note the * single quotes surrounding Email.CONTENT_ITEM_TYPE. */ ContactsContract.Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'";
ถัดไป ให้กําหนดตัวแปรที่มีอาร์กิวเมนต์การเลือก ดังนี้
Kotlin
private var searchString: String? = null private val selectionArgs: Array<String> = arrayOf("")
Java
String searchString; String[] selectionArgs = { "" };
ใช้ onCreateLoader()
เมื่อระบุข้อมูลที่ต้องการและวิธีค้นหาแล้ว ให้กําหนดคําค้นหาในการใช้งาน onCreateLoader()
ส่งคืน CursorLoader
ใหม่จากรายการนี้
โดยใช้การฉายภาพ นิพจน์ข้อความการเลือก และอาร์เรย์การเลือก
อาร์กิวเมนต์ สำหรับ URI เนื้อหา ให้ใช้
Data.CONTENT_URI
เช่น
Kotlin
override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { // OPTIONAL: Makes search string into pattern searchString = "%$mSearchString%" searchString?.also { // Puts the search string into the selection criteria selectionArgs[0] = it } // Starts the query return activity?.let { CursorLoader( it, ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ) } ?: throw IllegalStateException() }
Java
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { // OPTIONAL: Makes search string into pattern searchString = "%" + searchString + "%"; // Puts the search string into the selection criteria selectionArgs[0] = searchString; // Starts the query return new CursorLoader( getActivity(), Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ); }
ข้อมูลโค้ดเหล่านี้เป็นพื้นฐานของการค้นหาแบบย้อนกลับแบบง่ายตามประเภทรายละเอียดที่เจาะจง เทคนิคนี้เป็นเทคนิคที่ดีที่สุดหากแอปของคุณมุ่งเน้นที่ข้อมูลประเภทหนึ่งๆ เช่น อีเมล และคุณต้องการอนุญาตให้ผู้ใช้ดูชื่อที่เชื่อมโยงกับข้อมูลนั้น
จับคู่รายชื่อติดต่อกับข้อมูลทุกประเภท
การเรียกรายชื่อติดต่อตามข้อมูลประเภทใดก็ตามจะแสดงรายชื่อติดต่อ หากข้อมูลใดรายชื่อติดต่อนั้นตรงกับ สตริงการค้นหา ซึ่งรวมถึงชื่อ อีเมล ที่อยู่ไปรษณีย์ หมายเลขโทรศัพท์ และอื่นๆ ซึ่งทำให้เกิดผลการค้นหาที่หลากหลาย ตัวอย่างเช่น หากสตริงการค้นหาคือ "Doe" การค้นหาประเภทข้อมูลใดก็ตามจะแสดงรายชื่อติดต่อ "John Doe" และรายชื่อติดต่อที่อาศัยอยู่ใน "Doe Street" ด้วย
หากต้องการใช้การดึงข้อมูลประเภทนี้ ให้ติดตั้งใช้งานโค้ดต่อไปนี้ก่อนตามที่ระบุไว้ในส่วนก่อนหน้า
- ขอสิทธิ์อ่านผู้ให้บริการ
- กำหนดเลย์เอาต์ ListView และรายการ
- กำหนด Fregment ที่แสดงรายการรายชื่อติดต่อ
- กําหนดตัวแปรส่วนกลาง
- เริ่มต้น Fragment
- ตั้งค่า CursorAdapter สำหรับ ListView
- ตั้งค่า Listener รายชื่อติดต่อที่เลือก
- กำหนดการฉายภาพ
-
ระบุค่าคงที่สำหรับดัชนีคอลัมน์เคอร์เซอร์
สำหรับการดึงข้อมูลประเภทนี้ คุณจะใช้ตารางเดียวกับที่ใช้ในส่วนจับคู่รายชื่อติดต่อตามชื่อและแสดงผลลัพธ์ ใช้ดัชนีคอลัมน์เดียวกันด้วย
- กำหนดเมธอด onItemClick()
- เริ่มต้นตัวโหลด
- ใช้ onLoadFinished() และ onLoaderReset()
ขั้นตอนต่อไปนี้จะแสดงรหัสเพิ่มเติมที่คุณต้องจับคู่สตริงการค้นหา ข้อมูลทุกประเภทและแสดงผลลัพธ์
นำเกณฑ์การเลือกออก
อย่ากำหนดค่าคงที่ SELECTION
หรือตัวแปร mSelectionArgs
คำขอเหล่านี้ไม่ได้ใช้ในการดึงข้อมูลประเภทนี้
ใช้งาน onCreateLoader()
ใช้ onCreateLoader()
โดยแสดงผล CursorLoader
ใหม่
คุณไม่จำเป็นต้องแปลงสตริงการค้นหาเป็นรูปแบบ เนื่องจากผู้ให้บริการรายชื่อติดต่อจะดำเนินการดังกล่าวโดยอัตโนมัติ ใช้
Contacts.CONTENT_FILTER_URI
เป็น URI พื้นฐาน และเพิ่มสตริงการค้นหาต่อท้ายด้วยการเรียก
Uri.withAppendedPath()
การใช้ URI นี้
ทริกเกอร์การค้นหาประเภทข้อมูลหนึ่งๆ โดยอัตโนมัติ ดังที่แสดงในตัวอย่างต่อไปนี้
Kotlin
override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> { /* * Appends the search string to the base URI. Always * encode search strings to ensure they're in proper * format. */ val contentUri: Uri = Uri.withAppendedPath( ContactsContract.Contacts.CONTENT_FILTER_URI, Uri.encode(searchString) ) // Starts the query return activity?.let { CursorLoader( it, contentUri, PROJECTION2, null, null, null ) } ?: throw IllegalStateException() }
Java
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { /* * Appends the search string to the base URI. Always * encode search strings to ensure they're in proper * format. */ Uri contentUri = Uri.withAppendedPath( Contacts.CONTENT_FILTER_URI, Uri.encode(searchString)); // Starts the query return new CursorLoader( getActivity(), contentUri, PROJECTION, null, null, null ); }
ข้อมูลโค้ดเหล่านี้เป็นพื้นฐานของแอปที่ทำการค้นหาอย่างกว้างๆ ของผู้ให้บริการ Contacts เทคนิคนี้มีประโยชน์สำหรับแอปที่ต้องการใช้ฟังก์ชันที่คล้ายกับ หน้าจอรายชื่อติดต่อของแอป People