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

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

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

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

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

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

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

संपर्कों की जानकारी देने वाली सेवा से संपर्कों की जानकारी पढ़ने के लिए, आपके ऐप्लिकेशन के पास 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 क्लास में तय किए गए कॉलम के नामों का इस्तेमाल करके, 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

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

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

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 के ज़रिए, मौजूदा लाइन का डेटा टाइप तय करना होगा. साथ ही, सब-टाइप का इस्तेमाल करने वाली लाइनों का डेटा स्टोर करना होगा. कर्सर को पढ़ने के बाद, हर डेटा टाइप को सब-टाइप के हिसाब से क्रम में लगाया जा सकता है और नतीजे दिखाए जा सकते हैं.

लोडर को शुरू करें

संपर्कों की जानकारी देने वाली कंपनी (और कॉन्टेंट की सेवा देने वाली सभी अन्य कंपनियों) से, हमेशा बैकग्राउंड थ्रेड में जानकारी पाएं. बैकग्राउंड में डेटा पाने के लिए, 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() तरीका लागू करें. जब Contacts Provider, क्वेरी के नतीजे दिखाता है, तो लोडर फ़्रेमवर्क, 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;
            ...
        }
    }

onLoaderReset() का तरीका तब लागू होता है, जब लोडर फ़्रेमवर्क को पता चलता है कि Cursor के नतीजे का डेटा बदल गया है. ऐसा होने पर, 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 वैल्यू खोजने के लिए, चुने गए टेक्स्ट में बदलाव करें.
क्रमित करने का क्रम
सिर्फ़ एक तरह की जानकारी चुनने पर, Data.MIMETYPE के हिसाब से, रिटर्न किए गए Cursor को ग्रुप न करें.

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

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

डेटा टाइप के लिए 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.Data में तय किए गए कॉलम के नामों के बजाय, क्लास ContactsContract.CommonDataKinds.Email में तय किए गए कॉलम के नामों का इस्तेमाल करता है. ईमेल के हिसाब से कॉलम के नाम इस्तेमाल करने से, कोड को पढ़ना आसान हो जाता है.

प्रोजेक्शन में, 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 ";