संपर्कों की सूची वापस पाना

इस लेसन में, आपको उन संपर्कों की सूची वापस पाने का तरीका बताया गया है जिनका डेटा, खोज स्ट्रिंग के पूरे या कुछ हिस्से से मेल खाता है. इसके लिए, इन तकनीकों का इस्तेमाल किया जाता है:

संपर्कों के नाम मैच करना
संपर्क के नाम के पूरे या कुछ डेटा से खोज स्ट्रिंग का मिलान करके, संपर्कों की सूची पाएं. संपर्क सूची, एक ही नाम के कई इंस्टेंस की अनुमति देता है. इसलिए, इस तकनीक से मिलते-जुलते नामों की सूची मिल सकती है.
किसी खास तरह के डेटा से मैच करना, जैसे कि फ़ोन नंबर
किसी खास तरह की जानकारी के डेटा से खोज स्ट्रिंग का मिलान करके, संपर्कों की सूची वापस पाएं. जैसे, ईमेल पता. उदाहरण के लिए, इस तकनीक की मदद से उन सभी संपर्कों की सूची बनाई जा सकती है जिनके ईमेल पते, खोज स्ट्रिंग से मेल खाते हैं.
किसी भी तरह के डेटा से मैच करना
खोज स्ट्रिंग को किसी भी तरह के डेटा से मैच करके, संपर्कों की सूची पाएं. इसमें नाम, फ़ोन नंबर, मोहल्ले का पता, ईमेल पता वगैरह शामिल है. उदाहरण के लिए, इस तकनीक की मदद से, किसी खोज स्ट्रिंग के लिए किसी भी तरह का डेटा स्वीकार किया जा सकता है. इसके बाद, उन संपर्कों की सूची बनाई जा सकती है जिनके लिए डेटा, स्ट्रिंग से मेल खाता है.

ध्यान दें: इस लेसन के सभी उदाहरणों में, संपर्क सूची से डेटा वापस पाने के लिए CursorLoader का इस्तेमाल किया गया है. CursorLoader, यूज़र इंटरफ़ेस (यूआई) थ्रेड से अलग थ्रेड पर अपनी क्वेरी चलाता है. इससे यह पक्का होता है कि क्वेरी की वजह से यूज़र इंटरफ़ेस (यूआई) के रिस्पॉन्स टाइम में देरी न हो और उपयोगकर्ता को खराब अनुभव न मिले. ज़्यादा जानकारी के लिए, Android ट्रेनिंग क्लास बैकग्राउंड में डेटा लोड करना देखें.

सेवा देने वाली कंपनी के डेटा को पढ़ने की अनुमति का अनुरोध करना

संपर्क सूची में किसी भी तरह की खोज करने के लिए, आपके ऐप्लिकेशन के पास 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 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"/>

यह एक्सएमएल, पहले से मौजूद Android ListView विजेट android:id/list का इस्तेमाल करता है.

यहां दिए गए एक्सएमएल का इस्तेमाल करके, आइटम लेआउट फ़ाइल contacts_list_item.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"/>

इस एक्सएमएल में, Android के पहले से मौजूद TextView विजेट android:text1 का इस्तेमाल किया गया है.

ध्यान दें: इस लेसन में, उपयोगकर्ता से खोज स्ट्रिंग पाने के लिए यूज़र इंटरफ़ेस (यूआई) के बारे में नहीं बताया गया है. ऐसा इसलिए है, क्योंकि हो सकता है कि आपको स्ट्रिंग को सीधे तौर पर न पाना हो. उदाहरण के लिए, उपयोगकर्ता को ऐसे संपर्कों को खोजने का विकल्प दिया जा सकता है जिनका नाम, आने वाले टेक्स्ट मैसेज में मौजूद स्ट्रिंग से मेल खाता हो.

आपने जो दो लेआउट फ़ाइलें लिखी हैं उनसे एक ऐसा यूज़र इंटरफ़ेस तय होता है जो ListView दिखाता है. अगले चरण में, ऐसा कोड लिखें जो इस यूआई का इस्तेमाल करके संपर्कों की सूची दिखाए.

संपर्कों की सूची दिखाने वाला फ़्रैगमेंट तय करना

संपर्कों की सूची दिखाने के लिए, सबसे पहले एक Fragment तय करें, जिसे Activity लोड करता है. Fragment का इस्तेमाल करना एक बेहतर तरीका है, क्योंकि इसकाFragment इस्तेमाल करके सूची दिखाई जा सकती है. साथ ही, Fragment का इस्तेमाल करके, सूची में से उपयोगकर्ता के चुने गए संपर्क की जानकारी दिखाई जा सकती है. इस तरीके का इस्तेमाल करके, इस लेसन में बताई गई किसी एक तकनीक को संपर्क की जानकारी वापस पाना लेसन में बताई गई किसी तकनीक के साथ जोड़ा जा सकता है.

Fragment से एक या उससे ज़्यादा Activity ऑब्जेक्ट इस्तेमाल करने का तरीका जानने के लिए, ट्रेनिंग क्लास फ़्रैगमेंट की मदद से डाइनैमिक यूज़र इंटरफ़ेस (यूआई) बनाएं पढ़ें.

Android फ़्रेमवर्क, संपर्क सूची के ख़िलाफ़ क्वेरी लिखने में आपकी मदद करता है. इसके लिए, यह ContactsContract नाम का कॉन्ट्रैक्ट क्लास उपलब्ध कराता है. इसमें, प्रोवाइडर को ऐक्सेस करने के लिए काम के कॉन्स्टेंट और तरीके तय किए जाते हैं. इस क्लास का इस्तेमाल करने पर, आपको कॉन्टेंट यूआरआई, टेबल के नाम या कॉलम के लिए अपने कॉन्स्टेंट तय नहीं करने पड़ते. इस क्लास का इस्तेमाल करने के लिए, यह स्टेटमेंट शामिल करें:

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 (एपीआई वर्शन 11) या इसके बाद का वर्शन ज़रूरी है. इसलिए, अपने ऐप्लिकेशन के minSdkVersion को 10 या इससे कम पर सेट करने से, Android Studio में Android Lint की चेतावनी जनरेट होती है. इस चेतावनी को बंद करने के लिए, FROM_COLUMNS की परिभाषा से पहले @SuppressLint("InlinedApi") एनोटेशन जोड़ें.

फ़्रैगमेंट शुरू करना

Fragment को शुरू करें. Android सिस्टम के लिए ज़रूरी, खाली और सार्वजनिक कंस्ट्रक्टर जोड़ें. साथ ही, कॉलबैक के तरीके onCreateView() में Fragment ऑब्जेक्ट के यूज़र इंटरफ़ेस (यूआई) को इनफ़्लेट करें. उदाहरण के लिए:

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 के लिए CursorAdapter सेट अप करना

SimpleCursorAdapter सेट अप करें, जो खोज के नतीजों को ListView से जोड़ता है. संपर्क दिखाने वाले ListView ऑब्जेक्ट को पाने के लिए, आपको Fragment की पैरंट गतिविधि का इस्तेमाल करके, Activity.findViewById() को कॉल करना होगा. setAdapter() को कॉल करते समय, माता-पिता की गतिविधि के Context का इस्तेमाल करें. उदाहरण के लिए:

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 से बाइंड करें. इसके लिए, onActivityCreated() में setOnItemClickListener() मेथड को कॉल करें. उदाहरण के लिए:

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, ListView के लिए OnItemClickListener है. इसलिए, अब आपको इसका ज़रूरी तरीका onItemClick() लागू करना होगा. यह तरीका, क्लिक इवेंट को मैनेज करता है. इसके बारे में अगले सेक्शन में बताया गया है.

प्रोजेक्शन तय करना

एक ऐसा कॉन्सटेंट तय करें जिसमें वे कॉलम शामिल हों जिन्हें आपको अपनी क्वेरी से वापस पाना है. ListView में मौजूद हर आइटम में, संपर्क का डिसप्ले नेम दिखता है. इसमें संपर्क के नाम का मुख्य फ़ॉर्म शामिल होता है. Android 3.0 (एपीआई वर्शन 11) और इसके बाद के वर्शन में, इस कॉलम का नाम Contacts.DISPLAY_NAME_PRIMARY है. इससे पहले के वर्शन में, इसका नाम Contacts.DISPLAY_NAME है.

Contacts._ID कॉलम का इस्तेमाल, SimpleCursorAdapter बाइंडिंग प्रोसेस करती है. Contacts._ID और LOOKUP_KEY का इस्तेमाल एक साथ करके, उपयोगकर्ता के चुने गए संपर्क के लिए कॉन्टेंट यूआरआई बनाया जाता है.

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;

चुनने की ज़रूरी शर्तें तय करना

अपनी पसंद का डेटा पाने के लिए, टेक्स्ट एक्सप्रेशन और वैरिएबल का कॉम्बिनेशन बनाएं. इससे सेवा देने वाली कंपनी को पता चलता है कि उसे किन डेटा कॉलम और वैल्यू को खोजना है.

टेक्स्ट एक्सप्रेशन के लिए, एक ऐसा कॉन्सटेंट तय करें जिसमें खोज कॉलम की सूची हो. हालांकि, इस एक्सप्रेशन में वैल्यू भी शामिल हो सकती हैं, लेकिन वैल्यू को "?" प्लेसहोल्डर के साथ दिखाना बेहतर तरीका है. डेटा वापस पाने के दौरान, प्लेसहोल्डर को किसी कलेक्शन की वैल्यू से बदल दिया जाता है. प्लेसहोल्डर के तौर पर "?" का इस्तेमाल करने से यह पक्का होता है कि खोज की खास जानकारी, एसक्यूएल कंपाइलेशन के बजाय बाइंडिंग से जनरेट की गई है. इससे, नुकसान पहुंचाने वाले एसक्यूएल इंजेक्शन की संभावना खत्म हो जाती है. उदाहरण के लिए:

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%" पैटर्न, "Thomas Jefferson" और "Jefferson Davis", दोनों से मैच करेगा.

तरीके से नया CursorLoader वापस पाएं. कॉन्टेंट यूआरआई के लिए, Contacts.CONTENT_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 में पुराना डेटा मौजूद है. मौजूदा Cursor के SimpleCursorAdapter रेफ़रंस को मिटाएं. अगर ऐसा नहीं किया जाता है, तो लोडर फ़्रेमवर्क 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 में दिखाता है. उपयोगकर्ता किसी संपर्क के नाम पर क्लिक करके उसे चुन सकता है. इससे एक लिसनर ट्रिगर होता है. इसमें संपर्क के डेटा के साथ आगे काम किया जा सकता है. उदाहरण के लिए, संपर्क की जानकारी वापस पाई जा सकती है. ऐसा करने का तरीका जानने के लिए, अगले लेसन किसी संपर्क की जानकारी वापस पाना पर जाएं.

खोज के लिए यूज़र इंटरफ़ेस के बारे में ज़्यादा जानने के लिए, एपीआई गाइड खोज के लिए इंटरफ़ेस बनाना पढ़ें.

इस सबक के बाकी सेक्शन में, संपर्क सूची में संपर्क ढूंढने के अन्य तरीके बताए गए हैं.

किसी खास तरह के डेटा के हिसाब से संपर्क मैच करना

इस तकनीक की मदद से, यह तय किया जा सकता है कि आपको किस तरह का डेटा मैच करना है. नाम से संपर्क की जानकारी हासिल करना, इस तरह की क्वेरी का एक उदाहरण है. हालांकि, किसी संपर्क से जुड़े किसी भी तरह के डेटा के लिए भी ऐसा किया जा सकता है. उदाहरण के लिए, ऐसे संपर्कों को वापस पाया जा सकता है जिनका पिन कोड एक जैसा है. इस मामले में, खोज स्ट्रिंग को पिन कोड वाली लाइन में सेव किए गए डेटा से मैच करना होगा.

इस तरह से डेटा वापस पाने के लिए, पहले यहां दिया गया कोड लागू करें. इसके बारे में पिछले सेक्शन में बताया गया है:

  • सेवा देने वाली कंपनी की जानकारी ऐक्सेस करने की अनुमति का अनुरोध करें.
  • ListView और आइटम लेआउट तय करें.
  • संपर्कों की सूची दिखाने वाला फ़्रैगमेंट तय करें.
  • ग्लोबल वैरिएबल तय करें.
  • फ़्रैगमेंट को शुरू करें.
  • ListView के लिए CursorAdapter सेट अप करें.
  • चुने गए संपर्क के लिए लिसनर सेट करें.
  • Cursor कॉलम इंडेक्स के लिए कॉन्स्टेंट तय करें.

    भले ही, डेटा किसी दूसरी टेबल से वापस लाया जा रहा हो, लेकिन प्रोजेक्शन में कॉलम का क्रम एक जैसा होता है. इसलिए, Cursor के लिए एक जैसे इंडेक्स इस्तेमाल किए जा सकते हैं.

  • onItemClick() तरीके को तय करें.
  • लोडर को शुरू करें.
  • onLoadFinished() और onLoaderReset() को लागू करें.

यहां दिए गए चरणों में, आपको वह अतिरिक्त कोड दिखेगा जिसकी ज़रूरत आपको किसी खोज स्ट्रिंग को खास तरह के डेटा से मैच करने और नतीजे दिखाने के लिए होगी.

डेटा टाइप और टेबल चुनना

ज़्यादा जानकारी वाले किसी खास तरह के डेटा को खोजने के लिए, आपको डेटा टाइप के लिए कस्टम एमआईएमई टाइप की वैल्यू पता होनी चाहिए. हर डेटा टाइप के लिए, यूनीक एमआईएमई टाइप वैल्यू होती है. इसे डेटा टाइप से जुड़े ContactsContract.CommonDataKinds के सबक्लास में कॉन्स्टेंट CONTENT_ITEM_TYPE के तौर पर तय किया जाता है. सबक्लास के नाम से उनके डेटा टाइप का पता चलता है. उदाहरण के लिए, ईमेल डेटा की सबक्लास ContactsContract.CommonDataKinds.Email है और ईमेल डेटा के लिए कस्टम एमआईएमई टाइप को कॉन्सटैंट 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 कॉलम का इस्तेमाल करें.
  • खोज स्ट्रिंग, जिसे सिलेक्शन क्लॉज़ में "?" वर्ण के तौर पर दिखाया जाता है.
  • उस कॉलम का नाम जिसमें कस्टम एमआईएमई टाइप की वैल्यू शामिल है. यह नाम हमेशा Data.MIMETYPE होता है.
  • डेटा टाइप के लिए कस्टम एमआईएमई टाइप की वैल्यू. जैसा कि पहले बताया गया है, यह ContactsContract.CommonDataKinds सबक्लास में कॉन्स्टेंट CONTENT_ITEM_TYPE है. उदाहरण के लिए, ईमेल डेटा के लिए 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 दिखाएं. इसके लिए, अपने प्रोजेक्शन, चुने गए टेक्स्ट एक्सप्रेशन, और चुने गए कलेक्शन को आर्ग्युमेंट के तौर पर इस्तेमाल करें. कॉन्टेंट यूआरआई के लिए, 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 और आइटम लेआउट तय करें.
  • संपर्कों की सूची दिखाने वाला फ़्रैगमेंट तय करें.
  • ग्लोबल वैरिएबल तय करें.
  • फ़्रैगमेंट को शुरू करें.
  • ListView के लिए CursorAdapter सेट अप करें.
  • चुने गए संपर्क के लिए लिसनर सेट करें.
  • प्रोजेक्शन तय करें.
  • कर्सर कॉलम इंडेक्स के लिए कॉन्सटेंट तय करें.

    इस तरह की जानकारी पाने के लिए, उसी टेबल का इस्तेमाल किया जा रहा है जिसका इस्तेमाल आपने नाम के हिसाब से किसी संपर्क से जुड़ी जानकारी ढूंढना और नतीजे दिखाना सेक्शन में किया था. एक जैसे कॉलम इंडेक्स का भी इस्तेमाल करें.

  • onItemClick() तरीके को तय करें.
  • लोडर को शुरू करें.
  • onLoadFinished() और onLoaderReset() को लागू करें.

यहां दिए गए चरणों में, आपको वह अतिरिक्त कोड दिखाया गया है जिसकी ज़रूरत आपको किसी भी तरह के डेटा से खोज स्ट्रिंग का मिलान करने और नतीजे दिखाने के लिए होती है.

चुनने की ज़रूरी शर्तें हटाना

SELECTION कॉन्सटेंट या mSelectionArgs वैरिएबल को तय न करें. इस तरह की जानकारी पाने के लिए, इनका इस्तेमाल नहीं किया जाता.

onCreateLoader() को लागू करना

onCreateLoader() तरीका लागू करें, जिससे नया CursorLoader मिलता है. आपको खोज स्ट्रिंग को पैटर्न में बदलने की ज़रूरत नहीं है, क्योंकि संपर्क सूची ऐसा अपने-आप करता है. Contacts.CONTENT_FILTER_URI को बेस यूआरआई के तौर पर इस्तेमाल करें. साथ ही, Uri.withAppendedPath() को कॉल करके, अपनी सर्च स्ट्रिंग को इसमें जोड़ें. इस यूआरआई का इस्तेमाल करने पर, किसी भी डेटा टाइप को खोजने की प्रोसेस अपने-आप ट्रिगर हो जाती है. इसके बारे में यहां दिए गए उदाहरण में बताया गया है:

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

ये कोड स्निपेट, ऐसे ऐप्लिकेशन का आधार हैं जो संपर्क सूची में बड़े पैमाने पर खोज करता है. यह तकनीक उन ऐप्लिकेशन के लिए काम की है जो People ऐप्लिकेशन की संपर्क सूची स्क्रीन की तरह ही सुविधा लागू करना चाहते हैं.