किसी संपर्क की जानकारी वापस पाना

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

इस सबक में दिए गए चरणों के लिए, यह मान लिया जाता है कि आपके पास पहले से ही a ContactsContract.Contacts में, उपयोगकर्ता के चुने गए संपर्क की पंक्ति मौजूद है. संपर्कों के नाम पाने का तरीका बताने वाले सबक में, संपर्कों की सूची पाने का तरीका बताया गया है.

किसी संपर्क की पूरी जानकारी पाना

किसी संपर्क की पूरी जानकारी पाने के लिए, ContactsContract.Data टेबल में उन पंक्तियों को खोजें जिनमें संपर्क का LOOKUP_KEY शामिल हो. यह कॉलम ContactsContract.Data टेबल में उपलब्ध है, क्योंकि Contacts Provider, ContactsContract.Contacts टेबल और ContactsContract.Data टेबल के बीच, इंप्लिसिट जॉइन बनाता है. LOOKUP_KEY कॉलम के बारे में ज़्यादा जानकारी, संपर्कों के नाम पाने का तरीका बताने वाले सबक में दी गई है.

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

अनुमतियों का अनुरोध करना

Contacts Provider से जानकारी पढ़ने के लिए, आपके ऐप्लिकेशन के पास READ_CONTACTS की अनुमति होनी चाहिए. यह अनुमति पाने के लिए, अपनी मेनिफ़ेस्ट फ़ाइल में <manifest> का यह चाइल्ड एलिमेंट जोड़ें:

    <uses-permission android:name="android.permission.READ_CONTACTS" />

प्रोजेक्शन सेट अप करना

किसी पंक्ति में मौजूद डेटा के टाइप के हिसाब से, उसमें कुछ कॉलम या कई कॉलम इस्तेमाल किए जा सकते हैं. इसके अलावा, डेटा के टाइप के हिसाब से, डेटा अलग-अलग कॉलम में होता है. यह पक्का करने के लिए कि आपको सभी संभावित डेटा टाइप के लिए, सभी संभावित कॉलम मिलें, आपको अपने प्रोजेक्शन में कॉलम के सभी नाम जोड़ने होंगे. अगर नतीजे वाले Cursor को ListView से बाइंड किया जा रहा है, तो हमेशा Data._ID पाएं. ऐसा न करने पर, बाइंडिंग काम नहीं करेगी. Data.MIMETYPE भी पाएं, ताकि आपको पाई गई हर पंक्ति के डेटा टाइप की पहचान करने में मदद मिले. उदाहरण के लिए:

Kotlin

private val PROJECTION: Array<out String> = arrayOf(
        ContactsContract.Data._ID,
        ContactsContract.Data.MIMETYPE,
        ContactsContract.Data.DATA1,
        ContactsContract.Data.DATA2,
        ContactsContract.Data.DATA3,
        ContactsContract.Data.DATA4,
        ContactsContract.Data.DATA5,
        ContactsContract.Data.DATA6,
        ContactsContract.Data.DATA7,
        ContactsContract.Data.DATA8,
        ContactsContract.Data.DATA9,
        ContactsContract.Data.DATA10,
        ContactsContract.Data.DATA11,
        ContactsContract.Data.DATA12,
        ContactsContract.Data.DATA13,
        ContactsContract.Data.DATA14,
        ContactsContract.Data.DATA15
)

Java

    private static final String[] PROJECTION =
            {
                ContactsContract.Data._ID,
                ContactsContract.Data.MIMETYPE,
                ContactsContract.Data.DATA1,
                ContactsContract.Data.DATA2,
                ContactsContract.Data.DATA3,
                ContactsContract.Data.DATA4,
                ContactsContract.Data.DATA5,
                ContactsContract.Data.DATA6,
                ContactsContract.Data.DATA7,
                ContactsContract.Data.DATA8,
                ContactsContract.Data.DATA9,
                ContactsContract.Data.DATA10,
                ContactsContract.Data.DATA11,
                ContactsContract.Data.DATA12,
                ContactsContract.Data.DATA13,
                ContactsContract.Data.DATA14,
                ContactsContract.Data.DATA15
            };

यह प्रोजेक्शन, ContactsContract.Data टेबल में किसी पंक्ति के सभी कॉलम की जानकारी पाता है. इसके लिए, the ContactsContract.Data क्लास में तय किए गए कॉलम के नामों का इस्तेमाल किया जाता है.

इसके अलावा, ContactsContract.Data क्लास में तय किए गए या उससे इनहेरिट किए गए किसी अन्य कॉलम कॉन्स्टैंट का भी इस्तेमाल किया जा सकता है. हालांकि, ध्यान दें कि कॉलम SYNC1 से लेकर SYNC4 सिंक अडैप्टर के लिए इस्तेमाल किए जाते हैं. इसलिए, उनका डेटा काम का नहीं होता.

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

चुनने के क्लॉज़ के लिए कोई कॉन्स्टैंट, चुनने के आर्ग्युमेंट को सेव करने के लिए कोई अरे, और चुनने की वैल्यू को सेव करने के लिए कोई वैरिएबल तय करें. संपर्क ढूंढने के लिए, Contacts.LOOKUP_KEY कॉलम का इस्तेमाल करें. उदाहरण के लिए:

Kotlin

// Defines the selection clause
private const val SELECTION: String = "${ContactsContract.Data.LOOKUP_KEY} = ?"
...
// Defines the array to hold the search criteria
private val selectionArgs: Array<String> = arrayOf("")
/*
 * Defines a variable to contain the selection value. Once you
 * have the Cursor from the Contacts table, and you've selected
 * the desired row, move the row's LOOKUP_KEY value into this
 * variable.
 */
private var lookupKey: String? = null

Java

    // Defines the selection clause
    private static final String SELECTION = Data.LOOKUP_KEY + " = ?";
    // Defines the array to hold the search criteria
    private String[] selectionArgs = { "" };
    /*
     * Defines a variable to contain the selection value. Once you
     * have the Cursor from the Contacts table, and you've selected
     * the desired row, move the row's LOOKUP_KEY value into this
     * variable.
     */
    private lateinit var lookupKey: String

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

क्रम से लगाने का क्रम तय करना

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

Kotlin

/*
 * Defines a string that specifies a sort order of MIME type
 */
private const val SORT_ORDER = ContactsContract.Data.MIMETYPE

Java

    /*
     * Defines a string that specifies a sort order of MIME type
     */
    private static final String SORT_ORDER = ContactsContract.Data.MIMETYPE;

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

लोडर को शुरू करना

Contacts Provider (और अन्य सभी कॉन्टेंट प्रोवाइडर) से जानकारी पाने के लिए, हमेशा बैकग्राउंड थ्रेड का इस्तेमाल करें. बैकग्राउंड में जानकारी पाने के लिए, LoaderManager क्लास और LoaderManager.LoaderCallbacks इंटरफ़ेस से तय किए गए लोडर फ़्रेमवर्क का इस्तेमाल करें.

पंक्तियों की जानकारी पाने के लिए, लोडर फ़्रेमवर्क को initLoader() को कॉल करके शुरू करें. मेथड को कोई इंटिजर आइडेंटिफ़ायर पास करें. यह आइडेंटिफ़ायर, LoaderManager.LoaderCallbacks के तरीकों को पास किया जाता है. आइडेंटिफ़ायर की मदद से, किसी ऐप्लिकेशन में एक से ज़्यादा लोडर का इस्तेमाल किया जा सकता है. ऐसा इसलिए, क्योंकि इससे उनके बीच फ़र्क़ किया जा सकता है.

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

Kotlin

// Defines a constant that identifies the loader
private const val DETAILS_QUERY_ID: Int = 0

class DetailsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        // Initializes the loader framework
        loaderManager.initLoader(DETAILS_QUERY_ID, null, this)

Java

public class DetailsFragment extends Fragment implements
        LoaderManager.LoaderCallbacks<Cursor> {
    ...
    // Defines a constant that identifies the loader
    static int DETAILS_QUERY_ID = 0;
    ...
    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        // Initializes the loader framework
        getLoaderManager().initLoader(DETAILS_QUERY_ID, null, this);

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

onCreateLoader() मेथड को लागू करें. इसे लोडर फ़्रेमवर्क, initLoader() को कॉल करने के तुरंत बाद कॉल करता है. इस मेथड से CursorLoader लौटाएं. चूंकि, ContactsContract.Data टेबल को खोजा जा रहा है, इसलिए कॉन्टेंट यूआरआई के तौर पर, Data.CONTENT_URI कॉन्स्टैंट का इस्तेमाल करें. उदाहरण के लिए:

Kotlin

override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> {
    // Choose the proper action
    mLoader = when(loaderId) {
        DETAILS_QUERY_ID -> {
            // Assigns the selection parameter
            selectionArgs[0] = lookupKey
            // Starts the query
            activity?.let {
                CursorLoader(
                        it,
                        ContactsContract.Data.CONTENT_URI,
                        PROJECTION,
                        SELECTION,
                        selectionArgs,
                        SORT_ORDER
                )
            }
        }
        ...
    }
    return mLoader
}

Java

@Override
    public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
        // Choose the proper action
        switch (loaderId) {
            case DETAILS_QUERY_ID:
            // Assigns the selection parameter
            selectionArgs[0] = lookupKey;
            // Starts the query
            CursorLoader mLoader =
                    new CursorLoader(
                            getActivity(),
                            ContactsContract.Data.CONTENT_URI,
                            PROJECTION,
                            SELECTION,
                            selectionArgs,
                            SORT_ORDER
                    );
    }

onLoadFinished() और onLoaderReset() को लागू करना

onLoadFinished() मेथड को लागू करें. जब संपर्क सूची, क्वेरी के नतीजे लौटाता है, तब लोडर फ़्रेमवर्क, onLoadFinished() को कॉल करता है. उदाहरण के लिए:

Kotlin

    override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor) {
        when(loader.id) {
            DETAILS_QUERY_ID -> {
                /*
                 * Process the resulting Cursor here.
                 */
            }
            ...
        }
    }

Java

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        switch (loader.getId()) {
            case DETAILS_QUERY_ID:
                    /*
                     * Process the resulting Cursor here.
                     */
                }
                break;
            ...
        }
    }

जब लोडर फ़्रेमवर्क को पता चलता है कि नतीजे वाले डेटा Cursor के बैकअप में मौजूद डेटा बदल गया है, तब onLoaderReset() मेथड को कॉल किया जाता है. इस समय, मौजूदा रेफ़रंस को Cursor पर सेट करके हटाएं. ऐसा न करने पर, लोडर फ़्रेमवर्क पुराने Cursor को नहीं मिटाएगा. इससे मेमोरी लीक हो जाएगी. उदाहरण के लिए:

Kotlin

    override fun onLoaderReset(loader: Loader<Cursor>) {
        when (loader.id) {
            DETAILS_QUERY_ID -> {
                /*
                 * If you have current references to the Cursor,
                 * remove them here.
                 */
            }
            ...
        }
    }

Java

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        switch (loader.getId()) {
            case DETAILS_QUERY_ID:
                /*
                 * If you have current references to the Cursor,
                 * remove them here.
                 */
                }
                break;
    }

किसी संपर्क की खास जानकारी पाना

किसी संपर्क के लिए किसी खास डेटा टाइप की जानकारी पाने का तरीका, पूरी जानकारी पाने के तरीके जैसा ही होता है जैसे, सभी ईमेल पते. किसी संपर्क की पूरी जानकारी पाने के लिए, यहां दिए गए कोड में सिर्फ़ ये बदलाव करने होंगे:

प्रोजेक्शन
डेटा टाइप के हिसाब से कॉलम की जानकारी पाने के लिए, अपने प्रोजेक्शन में बदलाव करें. डेटा टाइप के हिसाब से, ContactsContract.CommonDataKinds सबक्लास में तय किए गए कॉलम के नाम वाले कॉन्स्टैंट का इस्तेमाल करने के लिए, प्रोजेक्शन में भी बदलाव करें.
चुनने की ज़रूरी शर्तें
अपने डेटा टाइप के हिसाब से, MIMETYPE वैल्यू खोजने के लिए, चुनने के टेक्स्ट में बदलाव करें.
क्रम से लगाने का क्रम
चूंकि, सिर्फ़ एक तरह की जानकारी चुनी जा रही है, इसलिए लौटाए गए Cursor को Data.MIMETYPE के हिसाब से ग्रुप न करें.

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

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

डेटा टाइप के लिए, ContactsContract.CommonDataKinds की सबक्लास में मौजूद कॉलम के नाम वाले कॉन्स्टैंट का इस्तेमाल करके, वे कॉलम तय करें जिनकी जानकारी आपको चाहिए. अगर आपको अपने Cursor को ListView से बाइंड करना है, तो _ID कॉलम की जानकारी ज़रूर पाएं. उदाहरण के लिए, ईमेल डेटा की जानकारी पाने के लिए, यह प्रोजेक्शन तय करें:

Kotlin

private val PROJECTION: Array<String> = arrayOf(
        ContactsContract.CommonDataKinds.Email._ID,
        ContactsContract.CommonDataKinds.Email.ADDRESS,
        ContactsContract.CommonDataKinds.Email.TYPE,
        ContactsContract.CommonDataKinds.Email.LABEL
)

Java

    private static final String[] PROJECTION =
            {
                ContactsContract.CommonDataKinds.Email._ID,
                ContactsContract.CommonDataKinds.Email.ADDRESS,
                ContactsContract.CommonDataKinds.Email.TYPE,
                ContactsContract.CommonDataKinds.Email.LABEL
            };

ध्यान दें कि इस प्रोजेक्शन में, क्लास ContactsContract.CommonDataKinds.Emailमें तय किए गए कॉलम के नामों के बजाय, क्लास ContactsContract.Data में तय किए गए कॉलम के नामों का इस्तेमाल किया गया है. ईमेल के हिसाब से कॉलम के नामों का इस्तेमाल करने से, कोड को पढ़ना आसान हो जाता है.

प्रोजेक्शन में, सबक्लासContactsContract.CommonDataKinds में तय किए गए अन्य कॉलम का भी इस्तेमाल किया जा सकता है.

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

खोज के लिए ऐसा टेक्स्ट एक्सप्रेशन तय करें जिससे किसी खास संपर्क के LOOKUP_KEY और आपको जिस जानकारी की ज़रूरत है उसके Data.MIMETYPE वाली पंक्तियां मिलें. MIMETYPE वैल्यू को सिंगल कोट में रखें. इसके लिए, कॉन्स्टैंट की शुरुआत और आखिर में, "'" (सिंगल-कोट) वर्ण जोड़ें. ऐसा न करने पर, प्रोवाइडर, कॉन्स्टैंट को स्ट्रिंग वैल्यू के बजाय वैरिएबल के नाम के तौर पर इंटरप्रेट करता है. इस वैल्यू के लिए, प्लेसहोल्डर का इस्तेमाल करने की ज़रूरत नहीं है, क्योंकि उपयोगकर्ता की दी गई वैल्यू के बजाय, कॉन्स्टैंट का इस्तेमाल किया जा रहा है. उदाहरण के लिए:

Kotlin

/*
 * Defines the selection clause. Search for a lookup key
 * and the Email MIME type
 */
private const val SELECTION =
        "${ContactsContract.Data.LOOKUP_KEY} = ? AND " +
        "${ContactsContract.Data.MIMETYPE} = '${Email.CONTENT_ITEM_TYPE}'"
...
// Defines the array to hold the search criteria
private val selectionArgs: Array<String> = arrayOf("")

Java

    /*
     * Defines the selection clause. Search for a lookup key
     * and the Email MIME type
     */
    private static final String SELECTION =
            Data.LOOKUP_KEY + " = ?" +
            " AND " +
            Data.MIMETYPE + " = " +
            "'" + Email.CONTENT_ITEM_TYPE + "'";
    // Defines the array to hold the search criteria
    private String[] selectionArgs = { "" };

क्रम से लगाने का क्रम तय करना

लौटाए गए Cursor के लिए, क्रम से लगाने का क्रम तय करें. चूंकि, किसी खास डेटा टाइप की जानकारी पाई जा रही है, इसलिए MIMETYPE के हिसाब से क्रम से न लगाएं. इसके बजाय, अगर खोजे जा रहे डेटा की जानकारी के टाइप में सबटाइप शामिल है, तो उसके हिसाब से क्रम से लगाएं. उदाहरण के लिए, ईमेल डेटा के लिए, Email.TYPE के हिसाब से क्रम से लगाया जा सकता है:

Kotlin

private const val SORT_ORDER: String = "${Email.TYPE} ASC"

Java

    private static final String SORT_ORDER = Email.TYPE + " ASC ";