لیستی از مخاطبین را بازیابی کنید

این درس به شما نشان می‌دهد که چگونه با استفاده از تکنیک‌های زیر، فهرستی از مخاطبین را که داده‌های آنها با تمام یا بخشی از یک رشته جستجو مطابقت دارد، بازیابی کنید:

نام مخاطبین را مطابقت دهید
با تطبیق رشته جستجو با تمام یا بخشی از اطلاعات نام مخاطب، فهرستی از مخاطبین را بازیابی کنید. ارائه دهنده مخاطبین به چندین نمونه با یک نام اجازه می دهد، بنابراین این تکنیک می تواند لیستی از موارد مشابه را برگرداند.
نوع خاصی از داده ها را مطابقت دهید، مانند شماره تلفن
فهرستی از مخاطبین را با تطبیق رشته جستجو با نوع خاصی از داده های جزئیات مانند آدرس ایمیل بازیابی کنید. به عنوان مثال، این تکنیک به شما امکان می دهد تمام مخاطبینی را که آدرس ایمیل آنها با رشته جستجو مطابقت دارد فهرست کنید.
هر نوع داده را مطابقت دهید
فهرستی از مخاطبین را با تطبیق رشته جستجو با هر نوع اطلاعات جزئی، از جمله نام، شماره تلفن، آدرس خیابان، آدرس ایمیل و غیره بازیابی کنید. برای مثال، این تکنیک به شما اجازه می‌دهد تا هر نوع داده‌ای را برای رشته جستجو بپذیرید و سپس مخاطبینی را که داده‌های آن‌ها با رشته مطابقت دارد فهرست کنید.

توجه: تمام مثال‌های این درس از CursorLoader برای بازیابی اطلاعات از Contacts Provider استفاده می‌کنند. یک CursorLoader پرس و جوی خود را روی رشته ای که از رشته رابط کاربری جدا است اجرا می کند. این تضمین می کند که پرس و جو زمان پاسخ UI را کاهش نمی دهد و باعث تجربه کاربری ضعیف نمی شود. برای اطلاعات بیشتر، کلاس آموزشی Android Loading Data in the Background را ببینید.

درخواست اجازه برای خواندن ارائه دهنده

برای انجام هر نوع جستجوی ارائه دهنده مخاطبین، برنامه شما باید مجوز 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 از ویجت Android ListView داخلی 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 از ویجت Android TextView داخلی android:text1 استفاده می کند.

توجه: این درس رابط کاربری برای دریافت رشته جستجو از کاربر را توصیف نمی کند، زیرا ممکن است بخواهید رشته را به طور غیر مستقیم دریافت کنید. برای مثال، می‌توانید به کاربر گزینه‌ای بدهید تا مخاطبینی را که نامشان با یک رشته در پیام متنی دریافتی مطابقت دارد، جستجو کند.

دو فایل طرح‌بندی که نوشته‌اید، یک رابط کاربری را تعریف می‌کنند که ListView را نشان می‌دهد. مرحله بعدی نوشتن کدی است که از این رابط کاربری برای نمایش لیستی از مخاطبین استفاده می کند.

قطعه ای را تعریف کنید که لیست مخاطبین را نمایش دهد

برای نمایش لیست مخاطبین، با تعریف Fragment که توسط یک Activity بارگیری می شود شروع کنید. استفاده از Fragment تکنیک انعطاف‌پذیرتری است، زیرا می‌توانید از یک Fragment برای نمایش لیست و از Fragment دوم برای نمایش جزئیات مخاطبی که کاربر از لیست انتخاب می‌کند استفاده کنید. با استفاده از این رویکرد، می توانید یکی از تکنیک های ارائه شده در این درس را با یکی از تکنیک های درس ترکیب کنید. جزئیات را برای یک مخاطب بازیابی کنید .

برای یادگیری نحوه استفاده از یک یا چند شیء Fragment از یک Activity ، کلاس آموزشی Build a dynamic UI with Fragments را بخوانید.

برای کمک به شما در نوشتن پرس‌و‌جوها در برابر ارائه‌دهنده مخاطبین، چارچوب Android یک کلاس قرارداد به نام ContactsContract ارائه می‌کند که ثابت‌ها و روش‌های مفیدی را برای دسترسی به ارائه‌دهنده تعریف می‌کند. وقتی از این کلاس استفاده می‌کنید، نیازی نیست که ثابت‌های خود را برای URI محتوا، نام جدول یا ستون‌ها تعریف کنید. برای استفاده از این کلاس، عبارت زیر را وارد کنید:

کاتلین

import android.provider.ContactsContract

جاوا

import android.provider.ContactsContract;

از آنجایی که کد CursorLoader برای بازیابی داده‌ها از ارائه‌دهنده استفاده می‌کند، باید مشخص کنید که رابط بارگیری LoaderManager.LoaderCallbacks را پیاده‌سازی کند. همچنین، برای کمک به شناسایی مخاطبی که کاربر از لیست نتایج جستجو انتخاب می کند، رابط آداپتور AdapterView.OnItemClickListener پیاده سازی کنید. به عنوان مثال:

کاتلین

...
import android.support.v4.app.Fragment
import android.support.v4.app.LoaderManager
import android.widget.AdapterView
...
class ContactsFragment :
        Fragment(),
        LoaderManager.LoaderCallbacks<Cursor>,
        AdapterView.OnItemClickListener {

جاوا

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

متغیرهای سراسری را تعریف کنید

متغیرهای سراسری را که در قسمت‌های دیگر کد استفاده می‌شوند تعریف کنید:

کاتلین

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

جاوا

    ...
    /*
     * 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 را راه اندازی کنید. سازنده خالی و عمومی مورد نیاز سیستم اندروید را اضافه کنید و UI شی Fragment را در روش callback onCreateView() اضافه کنید. به عنوان مثال:

کاتلین

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

جاوا

    // 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 که مخاطبین را نمایش می دهد، باید با استفاده از فعالیت والد Fragment Activity.findViewById() را فراخوانی کنید. هنگام فراخوانی setAdapter() از Context فعالیت والد استفاده کنید. به عنوان مثال:

کاتلین

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

جاوا

    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 را پیاده سازی می کند، همانطور که در بخش Define a Fragment نشان داده شده است که لیست مخاطبین را نمایش می دهد .

برای ادامه راه اندازی شنونده، با فراخوانی متد setOnItemClickListener() در onActivityCreated() آن را به ListView متصل کنید. به عنوان مثال:

کاتلین

    fun onActivityCreated(savedInstanceState:Bundle) {
        ...
        // Set the item click listener to be the current fragment.
        contactsList.onItemClickListener = this
        ...
    }

جاوا

    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 است.DISPLAY_NAME_PRIMARY ; در نسخه‌های قبلی، نام آن Contacts.DISPLAY_NAME است.DISPLAY_NAME.

ستون Contacts._ID توسط فرآیند اتصال SimpleCursorAdapter استفاده می شود. Contacts._ID و LOOKUP_KEY با هم برای ایجاد یک URI محتوا برای مخاطبی که کاربر انتخاب می کند استفاده می شود.

کاتلین

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

جاوا

...
@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 ثابت‌هایی تعریف کنید، زیرا ایندکس‌ها با ترتیب نام ستون‌ها در طرح‌بندی شما یکسان هستند. به عنوان مثال:

کاتلین

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

جاوا

// 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 را از بین می برد. به عنوان مثال:

کاتلین

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

جاوا

    // 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() اکشن را برای شنونده اجرا کنید:

کاتلین

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

جاوا

    @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() همانطور که در مثال زیر نشان داده شده است انجام دهید:

کاتلین

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)

جاوا

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%" با هر دو "Thomas Jefferson" و "Jefferson Davis" مطابقت دارد.

یک CursorLoader جدید را از متد برگردانید. برای URI محتوا، از Contacts.CONTENT_URI استفاده کنید. این URI به کل جدول اشاره دارد، همانطور که در مثال زیر نشان داده شده است:

کاتلین

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

جاوا

    ...
    @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 با نتایج جستجو به روز می کند:

کاتلین

    override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) {
        // Put the result Cursor in the adapter for the ListView
        cursorAdapter?.swapCursor(cursor)
    }

جاوا

    @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 را بازیافت نمی کند، که باعث نشت حافظه می شود. به عنوان مثال:

کاتلین

    override fun onLoaderReset(loader: Loader<Cursor>) {
        // Delete the reference to the existing Cursor
        cursorAdapter?.swapCursor(null)
    }

جاوا

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        // Delete the reference to the existing Cursor
        cursorAdapter.swapCursor(null);

    }

اکنون بخش‌های کلیدی یک برنامه را دارید که یک رشته جستجو را با نام مخاطبین مطابقت می‌دهد و نتیجه را در ListView برمی‌گرداند. کاربر می تواند روی نام مخاطب کلیک کند تا آن را انتخاب کند. این یک شنونده را فعال می کند که در آن می توانید بیشتر با داده های مخاطب کار کنید. به عنوان مثال، می توانید جزئیات مخاطب را بازیابی کنید. برای یادگیری نحوه انجام این کار، با درس بعدی، بازیابی جزئیات برای یک مخاطب ، ادامه دهید.

برای کسب اطلاعات بیشتر در مورد رابط های کاربری جستجو، راهنمای API ایجاد رابط جستجو را بخوانید.

بخش‌های باقی‌مانده در این درس راه‌های دیگری برای یافتن مخاطبین در ارائه‌دهنده مخاطبین را نشان می‌دهند.

مخاطب را با نوع خاصی از داده مطابقت دهید

این تکنیک به شما امکان می دهد نوع داده ای را که می خواهید مطابقت دهید مشخص کنید. بازیابی بر اساس نام نمونه خاصی از این نوع پرس و جو است، اما می توانید این کار را برای هر یک از انواع داده های جزئیات مرتبط با یک مخاطب نیز انجام دهید. به عنوان مثال، می توانید مخاطبینی را که کد پستی خاصی دارند، بازیابی کنید. در این مورد، رشته جستجو باید با داده های ذخیره شده در ردیف کد پستی مطابقت داشته باشد.

برای پیاده سازی این نوع بازیابی، ابتدا کد زیر را همانطور که در قسمت های قبلی ذکر شده است پیاده سازی کنید:

  • درخواست اجازه برای خواندن ارائه دهنده.
  • ListView و طرح بندی آیتم ها را تعریف کنید.
  • قطعه ای را تعریف کنید که لیست مخاطبین را نمایش دهد.
  • متغیرهای سراسری را تعریف کنید.
  • Fragment را مقداردهی اولیه کنید.
  • CursorAdapter را برای ListView تنظیم کنید.
  • شنونده مخاطب انتخابی را تنظیم کنید.
  • برای شاخص های ستون مکان نما، ثابت ها را تعریف کنید.

    اگرچه داده‌ها را از جدول دیگری بازیابی می‌کنید، ترتیب ستون‌ها در پروژکشن یکسان است، بنابراین می‌توانید از همان شاخص‌ها برای مکان‌نما استفاده کنید.

  • متد onItemClick() را تعریف کنید.
  • لودر را راه اندازی کنید.
  • onLoadFinished() و onLoaderReset را پیاده سازی کنید.

مراحل زیر کد اضافی مورد نیاز برای تطبیق یک رشته جستجو با نوع خاصی از داده های جزئیات و نمایش نتایج را به شما نشان می دهد.

نوع داده و جدول را انتخاب کنید

برای جستجوی نوع خاصی از داده های جزئیات، باید مقدار نوع MIME سفارشی برای نوع داده را بدانید. هر نوع داده دارای یک مقدار نوع MIME منحصر به فرد است که توسط یک CONTENT_ITEM_TYPE ثابت در زیر کلاس ContactsContract.CommonDataKinds مرتبط با نوع داده تعریف شده است. زیر کلاس ها دارای نام هایی هستند که نوع داده آنها را نشان می دهد. برای مثال، کلاس فرعی برای داده‌های ایمیل، ContactsContract.CommonDataKinds.Email است و نوع MIME سفارشی برای داده‌های ایمیل با ثابت Email.CONTENT_ITEM_TYPE تعریف می‌شود.

برای جستجوی خود از جدول ContactsContract.Data استفاده کنید. تمام ثابت هایی که برای طرح ریزی، بند انتخاب و ترتیب مرتب سازی نیاز دارید در این جدول تعریف شده یا به ارث برده می شوند.

فرافکنی را تعریف کنید

برای تعریف یک طرح، یک یا چند ستون تعریف شده در ContactsContract.Data یا کلاس هایی که از آنها به ارث می رسد را انتخاب کنید. ارائه دهنده Contacts قبل از بازگرداندن ردیف ها، یک اتصال ضمنی بین ContactsContract.Data و سایر جداول انجام می دهد. به عنوان مثال:

کاتلین

@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
)

جاوا

    @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 است. با الحاق یک کاراکتر " ' " (تک نقل قول) به ابتدا و انتهای ثابت، مقدار را در گیومه های تکی قرار دهید. در غیر این صورت، ارائه دهنده مقدار را به عنوان یک نام متغیر به جای یک مقدار رشته تفسیر می کند. برای این مقدار نیازی به استفاده از نگهدارنده مکان ندارید، زیرا از یک مقدار ثابت به جای یک مقدار عرضه شده توسط کاربر استفاده می کنید.

به عنوان مثال:

کاتلین

/*
 * 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}'"

جاوا

    /*
     * 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 + "'";

سپس، متغیرهایی را تعریف کنید که حاوی آرگومان انتخاب باشند:

کاتلین

    private var searchString: String? = null
    private val selectionArgs: Array<String> = arrayOf("")

جاوا

    String searchString;
    String[] selectionArgs = { "" };

پیاده سازی onCreateLoader()

اکنون که داده‌های مورد نظر و نحوه یافتن آن را مشخص کرده‌اید، در پیاده‌سازی onCreateLoader() کوئری تعریف کنید. یک CursorLoader جدید را از این روش با استفاده از طرح ریزی، بیان متن انتخابی و آرایه انتخاب به عنوان آرگومان برگردانید. برای URI محتوا، از Data.CONTENT_URI استفاده کنید. به عنوان مثال:

کاتلین

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

جاوا

@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" را برمی گرداند. همچنین مخاطبینی را که در «خیابان دو» زندگی می‌کنند برمی‌گرداند.

برای پیاده سازی این نوع بازیابی، ابتدا کد زیر را همانطور که در قسمت های قبلی ذکر شده است پیاده سازی کنید:

  • درخواست اجازه برای خواندن ارائه دهنده.
  • ListView و طرح بندی آیتم ها را تعریف کنید.
  • قطعه ای را تعریف کنید که لیست مخاطبین را نمایش دهد.
  • متغیرهای سراسری را تعریف کنید.
  • Fragment را مقداردهی اولیه کنید.
  • CursorAdapter را برای ListView تنظیم کنید.
  • شنونده مخاطب انتخابی را تنظیم کنید.
  • فرافکنی را تعریف کنید.
  • برای شاخص های ستون مکان نما، ثابت ها را تعریف کنید.

    برای این نوع بازیابی، از همان جدولی استفاده می‌کنید که در بخش تطبیق یک مخاطب با نام و فهرست کردن نتایج استفاده کردید. از همان شاخص های ستون نیز استفاده کنید.

  • متد onItemClick() را تعریف کنید.
  • لودر را راه اندازی کنید.
  • onLoadFinished() و onLoaderReset را پیاده سازی کنید.

مراحل زیر کد اضافی مورد نیاز برای تطبیق یک رشته جستجو با هر نوع داده و نمایش نتایج را به شما نشان می دهد.

معیارهای انتخاب را حذف کنید

ثابت های SELECTION یا متغیر mSelectionArgs را تعریف نکنید. اینها در این نوع بازیابی استفاده نمی شوند.

پیاده سازی onCreateLoader()

متد onCreateLoader() را پیاده سازی کنید و یک CursorLoader جدید را برگردانید. شما نیازی به تبدیل رشته جستجو به یک الگو ندارید، زیرا ارائه دهنده مخاطبین این کار را به صورت خودکار انجام می دهد. از Contacts.CONTENT_FILTER_URI به عنوان URI پایه استفاده کنید و رشته جستجوی خود را با فراخوانی Uri.withAppendedPath() به آن اضافه کنید. استفاده از این URI به طور خودکار جستجو برای هر نوع داده را آغاز می کند، همانطور که در مثال زیر نشان داده شده است:

کاتلین

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

جاوا

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

این قطعه کد اساس برنامه ای است که جستجوی گسترده ای در ارائه دهنده مخاطبین انجام می دهد. این تکنیک برای برنامه‌هایی مفید است که می‌خواهند عملکردی مشابه صفحه فهرست مخاطبین برنامه People پیاده‌سازی کنند.