يوضح هذا الدرس كيفية استرداد قائمة بجهات الاتصال التي تتطابق بياناتها مع كل أو جزء من سلسلة البحث، باستخدام الأساليب التالية:
- مطابقة أسماء جهات الاتصال
- استرداد قائمة بجهات الاتصال من خلال مطابقة سلسلة البحث مع كل بيانات اسم جهة الاتصال أو جزء منها يسمح مقدّم جهات الاتصال بمثيلات متعدّدة من الاسم نفسه، لذا يمكن أن تؤدي هذه الأسلوب إلى عرض قائمة بالمطابقات.
- مطابقة نوع معيّن من البيانات، مثل رقم هاتف
- يمكنك استرداد قائمة بجهات الاتصال من خلال مطابقة سلسلة البحث مع نوع معيّن من بيانات التفصيل ، مثل عنوان بريد إلكتروني. على سبيل المثال، يتيح لك هذا الأسلوب سرد جميع جهات الاتصال التي يطابق عنوان بريدها الإلكتروني سلسلة البحث.
- مطابقة أي نوع من البيانات
- يمكنك استرداد قائمة بجهات الاتصال من خلال مطابقة سلسلة البحث مع أي نوع من البيانات التفصيلية، بما في ذلك الاسم ورقم الهاتف وعنوان الشارع وعنوان البريد الإلكتروني وما إلى ذلك. على سبيل المثال، تتيح لك هذه التقنية قبول أي نوع من البيانات لسلسلة بحث، ثم إدراج جهات الاتصال التي تتطابق البيانات فيها مع السلسلة.
ملاحظة: تستخدِم جميع الأمثلة في هذا الدرس CursorLoader
لطلب البيانات من "مقدّم جهات الاتصال". يُجري CursorLoader
طلب البحث في سلسله محادثات
منفصلة عن سلسلة محادثات واجهة المستخدم. يضمن ذلك ألّا يؤدي طلب البحث إلى إبطاء واجهة المستخدم.
وقت الاستجابة ويسبب ترك انطباع سيئ لدى المستخدم. لمزيد من المعلومات، راجع
حصة التدريب
تحميل البيانات في الخلفية:
طلب إذن للاطّلاع على مقدّم الخدمة
لإجراء أي نوع من البحث في "موفِّر جهات الاتصال"، يجب أن يكون لدى تطبيقك إذن
READ_CONTACTS
.
لطلب هذا الإجراء، يجب إضافة هذا
<uses-permission>
إلى ملف البيان كعنصر ثانوي في
<manifest>
:
<uses-permission android:name="android.permission.READ_CONTACTS" />
مطابقة جهة اتصال حسب الاسم وعرض النتائج
تحاول هذه التقنية مطابقة سلسلة بحث مع اسم جهة اتصال أو جهات اتصال في جدول ContactsContract.Contacts
لجهة الاتصال. عادةً ما تريد
عرض النتائج في ListView
، للسماح للمستخدم بالاختيار من بين
جهات الاتصال المطابقة.
تحديد تنسيق ListView وتنسيقات العناصر
لعرض نتائج البحث في ListView
، تحتاج إلى ملف تنسيق أساسي
يحدِّد واجهة المستخدم بالكامل بما في ذلك 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
.
ملاحظة: لا يصف هذا الدرس واجهة المستخدم للحصول على سلسلة بحث من مستخدم التطبيق، لأنّك قد تحتاج إلى الحصول على السلسلة بشكل غير مباشر. على سبيل المثال، يمكنك منح المستخدم خيارًا للبحث عن جهات الاتصال التي يتطابق اسمها مع سلسلة في رسالة نصية واردة.
يحدد ملفا التخطيط اللذان كتبتهما واجهة مستخدم تعرض
ListView
الخطوة التالية هي كتابة رمز برمجي يستخدم واجهة المستخدم هذه لعرض
قائمة بجهات الاتصال.
تحديد جزء يعرض قائمة جهات الاتصال
لعرض قائمة جهات الاتصال، ابدأ بتحديد Fragment
يتم تحميله من خلال Activity
استخدام
والأسلوب Fragment
هو أسلوب أكثر مرونة، لأنه يمكنك استخدام
واحد Fragment
لعرض القائمة والثانية
Fragment
لعرض تفاصيل جهة اتصال لدى المستخدم
تختار من القائمة. باستخدام هذا النهج، يمكنك الجمع بين إحدى التقنيات المعروضة في
هذا الدرس وإحدى التقنيات الواردة في الدرس
استرداد تفاصيل جهة اتصال.
لمعرفة كيفية استخدام عنصر واحد أو أكثر من عناصر Fragment
من
Activity
، يُرجى قراءة حصة التدريب
إنشاء واجهة مستخدم ديناميكية باستخدام أجزاء من.
لمساعدتك في كتابة طلبات بحث مقابل "مقدِّم جهات الاتصال"، يوفّر إطار عمل Android
فئة العقود تسمى ContactsContract
، والتي تحدد معلومات مفيدة
الثوابت وطرق الوصول إلى الموفر. عند استخدام هذا الصف، لن تضطر إلى
تحديد الثوابت الخاصة بك لمعرفات الموارد المنتظمة (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
يتطلّب الإصدار 3.0 من نظام التشغيل Android (المستوى 11 لواجهة برمجة التطبيقات) أو إصدارًا أحدث، سيؤدي ضبط minSdkVersion
في
تطبيقك على 10 أو إصدار أقدم إلى ظهور تحذير Android Lint في
"استوديو Android". لإيقاف هذا التحذير، أضِف التعليق التوضيحي
@SuppressLint("InlinedApi")
قبل تعريف FROM_COLUMNS
.
تهيئة الجزء
فعِّل Fragment
. أضِف أسلوب الإنشاء العلني والفارغ
الذي يتطلّبه نظام Android، ووسِّع واجهة مستخدم Fragment
obj في طريقة الاستدعاء 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); }
إعداد مهايئ المؤشر في 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); }
ضبط مستمع جهة الاتصال المحدّدة
عند عرض نتائج البحث، تريد عادةً السماح للمستخدم باختيار
جهة اتصال واحدة لإجراء المزيد من المعالجة. على سبيل المثال، عندما ينقر المستخدم على جهة اتصال، يمكنك
عرض عنوان جهة الاتصال على خريطة. لتوفير هذه الميزة، حدّدتَ أولاً واجهة
Fragment
باعتباره المستمع للنقرة من خلال تحديد أن الفئة
لتنفيذ AdapterView.OnItemClickListener
، كما هو موضح في القسم
تحديد جزء يعرض قائمة جهات الاتصال.
لمواصلة إعداد المستمع، اربطه بـ "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 (واجهة برمجة التطبيقات الإصدار 11) والإصدارات الأحدث،
يكون اسم هذا العمود
Contacts.DISPLAY_NAME_PRIMARY
; في الإصدارات السابقة لها، يكون اسمه
Contacts.DISPLAY_NAME
يتم استخدام العمود Contacts._ID
من خلال عملية ربط
SimpleCursorAdapter
.
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()
في قسم سابق، أعددت مستمع النقر على العنصر للعنصر ListView
.
الآن، نفِّذ الإجراء للمستمع من خلال تحديد الطريقة
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%"
مع كل من "توماس جيفرسون" و"جفرسون ديفيس".
إرجاع 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
. يمكن للمستخدم النقر على اسم جهة اتصال لاختيارها.
يؤدي ذلك إلى تشغيل مستمع يمكنك من خلاله إجراء المزيد من الإجراءات باستخدام بيانات جهة الاتصال. على سبيل المثال:
يمكنك استرداد تفاصيل جهة الاتصال. لمعرفة كيفية إجراء ذلك، تابع
استرداد تفاصيل جهة اتصال.
للمزيد من المعلومات حول واجهات المستخدم في "بحث Google"، اطّلِع على دليل واجهة برمجة التطبيقات. أنشئ واجهة بحث.
توضِّح الأقسام المتبقية في هذا الدرس طرقًا أخرى للعثور على جهات الاتصال في "مزوّد جهات الاتصال".
مطابقة جهة اتصال حسب نوع معيّن من البيانات
يتيح لك هذا الأسلوب تحديد نوع البيانات التي تريد مطابقتها. إنّ الاسترداد حسب الاسم هو مثال محدّد على هذا النوع من طلبات البحث، ولكن يمكنك أيضًا إجراء ذلك لأيّ من أنواع البيانات التفصيلية المرتبطة بجهة اتصال. على سبيل المثال، يمكنك استرداد جهات الاتصال التي تحتوي على رمز بريدي محدّد في هذه الحالة، يجب أن تتطابق سلسلة البحث مع البيانات المخزنة في رمز بريدي الصف.
لتنفيذ هذا النوع من الاسترجاع، نفذ أولاً التعليمة البرمجية التالية، كما هو موضح في الأقسام السابقة:
- اطلب إذن قراءة مقدّم الخدمة.
- تحديد تنسيق ListView وتخطيطات العناصر
- حدِّد مقتطفًا يعرض قائمة جهات الاتصال.
- حدِّد المتغيّرات العامة.
- تهيئة الجزء.
- إعداد مهايئ المؤشر في ListView.
- اضبط مستمع جهة الاتصال المحدّدة.
-
تحديد الثوابت لفهارس عمود المؤشر.
على الرغم من أنّك تسترجع البيانات من جدول مختلف، فإنّ ترتيب الأعمدة في الإسقاط هو نفسه، لذا يمكنك استخدام الفهارس نفسها لعنصر المؤشر.
- قم بتعريف طريقة onItemClick().
- فعِّل أداة التحميل.
- نفِّذ الدالتَين onLoadFinished() وonLoaderReset().
توضّح لك الخطوات التالية الرمز الإضافي الذي تحتاجه لمطابقة سلسلة بحث مع نوع معيّن من البيانات التفصيلية وعرض النتائج.
اختيار نوع البيانات والجدول
للبحث عن نوع معيّن من البيانات التفصيلية، عليك معرفة قيمة نوع MIME المخصّصة
لنوع البيانات. لكل نوع بيانات نوع MIME فريد
قيمة محددة بواسطة CONTENT_ITEM_TYPE
ثابت في الفئة الفرعية
السمة ContactsContract.CommonDataKinds
المرتبطة بنوع البيانات.
للفئات الفرعية أسماء تشير إلى نوع بياناتها؛ على سبيل المثال، الفئة الفرعية للبريد الإلكتروني
البيانات هي ContactsContract.CommonDataKinds.Email
، ويستخدم MIME المخصص
بيانات البريد الإلكتروني من خلال الثابت
Email.CONTENT_ITEM_TYPE
استخدِم جدول ContactsContract.Data
لإجراء البحث. يتم تحديد كل الثابتة
التي تحتاج إليها للعرض وعبارة الاختيار وترتيب الفرز في هذا الجدول أو
يتم اكتسابها منه.
تعريف الإسقاط
لتحديد إسقاط، اختَر عمودًا واحدًا أو أكثر من الأعمدة المحدّدة في
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 ); }
تعتمد مقتطفات الرمز هذه على إجراء بحث عكسي بسيط استنادًا إلى نوع معيّن من التفاصيل. البيانات. هذا هو أفضل أسلوب يمكن استخدامه إذا كان تطبيقك يركّز على نوع معيّن من البيانات، مثل مثل رسائل البريد الإلكتروني، وترغب في السماح للمستخدمين بالحصول على الأسماء المرتبطة بجزء من البيانات.
مطابقة جهة اتصال حسب أي نوع من البيانات
يؤدي استرداد جهة اتصال استنادًا إلى أي نوع من البيانات إلى عرض جهات الاتصال إذا كانت أي من بياناتها تتطابق مع سلسلة البحث، بما في ذلك الاسم وعنوان البريد الإلكتروني والعنوان البريدي ورقم الهاتف وما إلى ذلك. ويؤدي ذلك إلى ظهور مجموعة واسعة من نتائج البحث. على سبيل المثال، إذا كانت سلسلة البحث هي "خالد"، ثم يؤدي البحث عن أي نوع بيانات إلى عرض جهة الاتصال "سامح رضا"؛ كما يُرجعها جهات الاتصال التي تعيش في "شارع سليم".
لتنفيذ هذا النوع من الاسترجاع، نفذ أولاً التعليمة البرمجية التالية، كما هو موضح في الأقسام السابقة:
- اطلب إذن قراءة مقدّم الخدمة.
- تحديد تنسيق ListView وتخطيطات العناصر
- حدِّد مقتطفًا يعرض قائمة جهات الاتصال.
- حدِّد المتغيّرات العامة.
- تهيئة الجزء.
- إعداد مهايئ المؤشر في ListView.
- يمكنك ضبط أداة استماع جهة الاتصال المحددة.
- تحديد الإسقاط.
-
حدِّد ثوابت لفهرسة أعمدة المؤشر.
بالنسبة لهذا النوع من الاسترجاع، فإنك تستخدم نفس الجدول الذي استخدمته في القسم طابق جهة اتصال حسب الاسم واعرض النتائج. يمكنك استخدام فهارس الأعمدة نفسها أيضًا.
- قم بتعريف طريقة onItemClick().
- فعِّل أداة التحميل.
- نفِّذ onLoadFinished() وonLoaderReset().
توضّح لك الخطوات التالية الرمز الإضافي الذي تحتاجه لمطابقة سلسلة بحث مع أي نوع من البيانات وعرض النتائج.
إزالة معايير الاختيار
لا تحدِّد الثوابت SELECTION
أو المتغيّر mSelectionArgs
.
ولا تُستخدم هذه في هذا النوع من الاسترجاع.
تنفيذ onCreateLoader()
تنفيذ onCreateLoader()
، وهي عرض دالة CursorLoader
جديدة.
ولا تحتاج إلى تحويل سلسلة البحث إلى نمط، لأن مقدم جهات الاتصال
ذلك تلقائيًا. استخدِم
Contacts.CONTENT_FILTER_URI
كعنوان URI الأساسي، وألِف سلسلة البحث به من خلال استدعاء
Uri.withAppendedPath()
. يؤدي استخدام عنوان URL هذا
إلى بدء البحث تلقائيًا عن أي نوع بيانات، كما هو موضّح في المثال التالي:
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 ); }
مقتطفات الرمز هذه هي أساس تطبيق يُجري بحثًا واسعًا عن "مقدِّم جهات الاتصال". ويكون هذا الأسلوب مفيدًا للتطبيقات التي تريد تنفيذ وظائف مشابهة شاشة قائمة جهات الاتصال في تطبيق الأشخاص