संपर्क सूची

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

इस गाइड में इनके बारे में बताया गया है:

  • सेवा देने वाली कंपनी का बुनियादी स्ट्रक्चर.
  • डेटा देने वाली कंपनी से डेटा वापस पाने का तरीका.
  • सेवा देने वाली कंपनी के डेटा में बदलाव करने का तरीका.
  • अपने सर्वर से संपर्क सूची में डेटा सिंक करने के लिए, सिंक अडैप्टर लिखने का तरीका.

इस गाइड में यह मानकर चला गया है कि आपको Android कॉन्टेंट प्रोवाइडर के बारे में बुनियादी जानकारी है. Android कॉन्टेंट प्रोवाइडर के बारे में ज़्यादा जानने के लिए, कॉन्टेंट प्रोवाइडर की बुनियादी बातें गाइड पढ़ें.

संपर्क सूची उपलब्ध कराने वाला संगठन

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

पहली इमेज. संपर्क सूची की टेबल का स्ट्रक्चर.

इन तीन टेबल को आम तौर पर, इनकी अनुबंध क्लास के नाम से जाना जाता है. क्लास, कॉन्टेंट यूआरआई, कॉलम के नाम, और कॉलम की वैल्यू के लिए कॉन्स्टेंट तय करती हैं. इनका इस्तेमाल टेबल में किया जाता है:

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

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

रॉ कॉन्टैक्ट

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

किसी रॉ संपर्क का ज़्यादातर डेटा, ContactsContract.RawContacts टेबल में सेव नहीं किया जाता. इसके बजाय, इसे ContactsContract.Data टेबल में एक या उससे ज़्यादा लाइनों में सेव किया जाता है. डेटा की हर लाइन में एक कॉलम Data.RAW_CONTACT_ID होता है. इसमें, इसकी पैरंट ContactsContract.RawContacts लाइन की RawContacts._ID वैल्यू होती है.

रॉ संपर्क के अहम कॉलम

ContactsContract.RawContacts टेबल में मौजूद ज़रूरी कॉलम की सूची, टेबल 1 में दी गई है. कृपया टेबल के बाद दिए गए नोट पढ़ें:

पहली टेबल. कच्चे संपर्क की जानकारी वाले कॉलम.

कॉलम का नाम इस्तेमाल करें नोट
ACCOUNT_NAME उस खाता टाइप के खाते का नाम जो इस रॉ संपर्क का सोर्स है. उदाहरण के लिए, Google खाते का नाम, डिवाइस के मालिक के Gmail पतों में से एक होता है. ज़्यादा जानकारी के लिए, ACCOUNT_TYPE के बारे में अगली एंट्री देखें. इस नाम का फ़ॉर्मैट, खाते के टाइप के हिसाब से तय होता है. यह ज़रूरी नहीं है कि यह ईमेल पता हो.
ACCOUNT_TYPE यह उस खाते का टाइप है जिससे यह रॉ संपर्क मिला है. उदाहरण के लिए, Google खाते का खाता टाइप com.google है. अपने खाते के टाइप के साथ हमेशा उस डोमेन का आइडेंटिफ़ायर जोड़ें जिसका मालिकाना हक आपके पास है या जिसे कंट्रोल करने का अधिकार आपके पास है. इससे यह पक्का होगा कि आपके खाते का टाइप यूनीक हो. संपर्कों का डेटा उपलब्ध कराने वाले खाते में, आम तौर पर एक सिंक अडैप्टर जुड़ा होता है. यह संपर्क सूची के साथ सिंक करता है.
DELETED किसी रॉ संपर्क के लिए "मिटाया गया" फ़्लैग. इस फ़्लैग की मदद से, संपर्क सूची, पंक्ति को अंदरूनी तौर पर तब तक बनाए रख सकता है, जब तक कि सिंक अडैप्टर अपने सर्वर से पंक्ति को मिटा न दें. इसके बाद, वे रिपॉज़िटरी से पंक्ति को मिटा सकते हैं.

नोट

ContactsContract.RawContacts टेबल के बारे में यहां कुछ ज़रूरी बातें बताई गई हैं:

  • कच्चे संपर्क का नाम, ContactsContract.RawContacts में उसकी लाइन में सेव नहीं किया जाता. इसके बजाय, इसे ContactsContract.Data टेबल में ContactsContract.CommonDataKinds.StructuredName लाइन में सेव किया जाता है. रॉ संपर्क में, ContactsContract.Data टेबल में इस तरह की सिर्फ़ एक लाइन होती है.
  • चेतावनी: रॉ संपर्क की लाइन में अपने खाते में मौजूद डेटा इस्तेमाल करने के लिए, यह ज़रूरी है कि उसे पहले AccountManager में रजिस्टर किया गया हो. इसके लिए, उपयोगकर्ताओं को खातों की सूची में खाते का टाइप और खाते का नाम जोड़ने के लिए कहें. ऐसा न करने पर, संपर्क सूची आपकी रॉ कॉन्टैक्ट लाइन को अपने-आप मिटा देगा.

    उदाहरण के लिए, अगर आपको अपनी वेब-आधारित सेवा के लिए, संपर्क डेटा को बनाए रखने के लिए अपने ऐप्लिकेशन की ज़रूरत है, तो डोमेन com.example.dataservice का इस्तेमाल करें. साथ ही, अगर आपकी सेवा के लिए उपयोगकर्ता का खाता becky.sharp@dataservice.example.com है, तो आपके ऐप्लिकेशन को संपर्क की रॉ पंक्तियां जोड़ने से पहले, उपयोगकर्ता को खाता "टाइप" (com.example.dataservice) और खाता "नाम" (becky.smart@dataservice.example.com) जोड़ना होगा. दस्तावेज़ में, उपयोगकर्ता को इस ज़रूरी शर्त के बारे में बताया जा सकता है. इसके अलावा, उपयोगकर्ता को टाइप और नाम या दोनों जोड़ने के लिए कहा जा सकता है. खाते के टाइप और खाते के नामों के बारे में ज़्यादा जानकारी अगले सेक्शन में दी गई है.

कच्चे संपर्क डेटा के सोर्स

रॉ संपर्क कैसे काम करते हैं, यह समझने के लिए "एमिली डिकिंसन" नाम के उपयोगकर्ता का उदाहरण लें. उसके डिवाइस पर ये तीन उपयोगकर्ता खाते हैं:

  • emily.dickinson@gmail.com
  • emilyd@gmail.com
  • Twitter खाता "belle_of_amherst"

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

मान लें कि एमिली डिकिंसन ने ब्राउज़र विंडो खोली और emily.dickinson@gmail.com के तौर पर Gmail में लॉग इन किया. इसके बाद, उन्होंने Contacts खोला और "थॉमस हिगिंसन" को जोड़ा. बाद में, वह emilyd@gmail.com के तौर पर Gmail में लॉग इन करती है और "थॉमस हिगिंसन" को एक ईमेल भेजती है. इससे वह अपने-आप संपर्क के तौर पर जुड़ जाता है. वह Twitter पर "colonel_tom" (थॉमस हिगिंसन का Twitter आईडी) को भी फ़ॉलो करती है.

संपर्क सूची ऐप्लिकेशन, इस काम के बाद तीन रॉ संपर्क बनाता है:

  1. emily.dickinson@gmail.com से जुड़ा "थॉमस हिगिंसन" का रॉ कॉन्टैक्ट. उपयोगकर्ता खाते का टाइप Google है.
  2. emilyd@gmail.com से जुड़ा "थॉमस हिगिंसन" का दूसरा रॉ संपर्क. उपयोगकर्ता खाते का टाइप भी Google है. नाम पहले से मौजूद नाम से मिलता-जुलता होने के बावजूद, दूसरा रॉ संपर्क मौजूद है. इसकी वजह यह है कि व्यक्ति को किसी दूसरे उपयोगकर्ता खाते के लिए जोड़ा गया था.
  3. "belle_of_amherst" से जुड़ा "थॉमस हिगिंसन" का तीसरा रॉ संपर्क. उपयोगकर्ता खाते का टाइप Twitter है.

डेटा

जैसा कि पहले बताया गया है, रॉ संपर्क का डेटा, ContactsContract.Data लाइन में सेव होता है. यह लाइन, रॉ संपर्क की _ID वैल्यू से लिंक होती है. इससे एक ही रॉ संपर्क में, एक ही तरह के डेटा के कई उदाहरण मिल जाते हैं. जैसे, ईमेल पते या फ़ोन नंबर. उदाहरण के लिए, अगर emilyd@gmail.com के लिए "थॉमस हिगिंसन" (थॉमस हिगिंसन के लिए, Google खाते emilyd@gmail.com से जुड़ा रॉ कॉन्टैक्ट) के पास घर का ईमेल पता thigg@gmail.com और ऑफ़िस वाला ईमेल पता thomas.higginson@gmail.com है, तो संपर्क सूची, दोनों ईमेल पते की लाइनों को सेव करता है और उन्हें रॉ कॉन्टैक्ट से लिंक करता है.

ध्यान दें कि इस एक टेबल में अलग-अलग तरह का डेटा सेव किया गया है. डिस्प्ले नेम, फ़ोन नंबर, ईमेल, डाक पता, फ़ोटो, और वेबसाइट की ज़्यादा जानकारी वाली लाइनें, सभी ContactsContract.Data टेबल में मिलती हैं. इसे मैनेज करने के लिए, ContactsContract.Data टेबल में कुछ कॉलम के नाम जानकारी देने वाले हैं और कुछ के नाम सामान्य हैं. ब्यौरे वाले नाम के कॉलम में मौजूद कॉन्टेंट का मतलब एक ही होता है. भले ही, लाइन में मौजूद डेटा का टाइप कुछ भी हो. वहीं, सामान्य नाम वाले कॉलम में मौजूद कॉन्टेंट का मतलब, डेटा के टाइप के हिसाब से अलग-अलग होता है.

कॉलम के बारे में जानकारी देने वाले नाम

जानकारी देने वाले कॉलम के नामों के कुछ उदाहरण यहां दिए गए हैं:

RAW_CONTACT_ID
इस डेटा के लिए, रॉ संपर्क के _ID कॉलम की वैल्यू.
MIMETYPE
इस लाइन में सेव किए गए डेटा का टाइप, जिसे कस्टम एमआईएमई टाइप के तौर पर दिखाया जाता है. संपर्क सूची, ContactsContract.CommonDataKinds की सबक्लास में तय किए गए MIME टाइप का इस्तेमाल करती है. ये MIME टाइप ओपन सोर्स हैं. इनका इस्तेमाल, संपर्क सूची के साथ काम करने वाला कोई भी ऐप्लिकेशन या सिंक अडैप्टर कर सकता है.
IS_PRIMARY
अगर किसी रॉ संपर्क के लिए इस तरह की डेटा लाइन एक से ज़्यादा बार दिख सकती है, तो IS_PRIMARY कॉलम, उस डेटा लाइन को फ़्लैग करता है जिसमें टाइप के लिए प्राइमरी डेटा होता है. उदाहरण के लिए, अगर कोई उपयोगकर्ता किसी संपर्क के फ़ोन नंबर पर देर तक दबाता है और डिफ़ॉल्ट के तौर पर सेट करें चुनता है, तो उस नंबर वाली ContactsContract.Data लाइन के IS_PRIMARY कॉलम को शून्य से अलग वैल्यू पर सेट किया जाता है.

सामान्य कॉलम के नाम

आम तौर पर इस्तेमाल होने वाले 15 कॉलम होते हैं. इनके नाम DATA1 से लेकर DATA15 तक होते हैं. इसके अलावा, आम तौर पर इस्तेमाल होने वाले चार अन्य कॉलम SYNC1 से लेकर SYNC4 तक होते हैं. इनका इस्तेमाल सिर्फ़ सिंक अडैप्टर को करना चाहिए. कॉलम के नाम वाले सामान्य कॉन्स्टेंट हमेशा काम करते हैं. इससे कोई फ़र्क़ नहीं पड़ता कि लाइन में किस तरह का डेटा है.

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

परंपरा के मुताबिक, DATA15 कॉलम को बाइनरी लार्ज ऑब्जेक्ट (बीएलओबी) डेटा सेव करने के लिए रिज़र्व किया जाता है. जैसे, फ़ोटो थंबनेल.

टाइप के हिसाब से कॉलम के नाम

किसी खास तरह की लाइन के कॉलम के साथ काम करने के लिए, संपर्क सूची, टाइप के हिसाब से कॉलम के नाम वाले कॉन्स्टेंट भी उपलब्ध कराता है. ये कॉन्स्टेंट, ContactsContract.CommonDataKinds की सबक्लास में तय किए जाते हैं. कॉन्स्टेंट, कॉलम के एक ही नाम को अलग-अलग कॉन्स्टेंट के नाम देते हैं. इससे आपको किसी खास टाइप की लाइन में मौजूद डेटा को ऐक्सेस करने में मदद मिलती है.

उदाहरण के लिए, ContactsContract.CommonDataKinds.Email क्लास, ContactsContract.Data लाइन के लिए टाइप के हिसाब से कॉलम के नाम वाले कॉन्स्टेंट तय करती है. इस लाइन का एमआईएमई टाइप Email.CONTENT_ITEM_TYPE है. क्लास में ईमेल पते वाले कॉलम के लिए, कॉन्स्टेंट ADDRESS मौजूद है. ADDRESS की असल वैल्यू "data1" है, जो कॉलम के सामान्य नाम के बराबर है.

चेतावनी: ContactsContract.Data टेबल में अपना कस्टम डेटा न जोड़ें. इसके लिए, ऐसी लाइन का इस्तेमाल करें जिसमें सेवा देने वाली कंपनी के पहले से तय किए गए MIME टाइप में से कोई एक टाइप हो. ऐसा करने से, आपका डेटा मिट सकता है या सेवा देने वाली कंपनी की सेवा ठीक से काम नहीं कर सकती. उदाहरण के लिए, आपको ऐसी लाइन नहीं जोड़नी चाहिए जिसमें एमआईएमई टाइप Email.CONTENT_ITEM_TYPE हो और जिसमें कॉलम DATA1 में ईमेल पते के बजाय उपयोगकर्ता नाम शामिल हो. अगर आपने लाइन के लिए, अपने हिसाब से बनाए गए कस्टम एमआईएमई टाइप का इस्तेमाल किया है, तो आपके पास टाइप के हिसाब से कॉलम के नाम तय करने का विकल्प होता है. साथ ही, अपनी ज़रूरत के हिसाब से कॉलम का इस्तेमाल किया जा सकता है.

दूसरी इमेज में दिखाया गया है कि ContactsContract.Data लाइन में, जानकारी देने वाले कॉलम और डेटा कॉलम कैसे दिखते हैं. साथ ही, टाइप के हिसाब से कॉलम के नाम, सामान्य कॉलम के नामों पर कैसे "ओवरले" होते हैं

टाइप के हिसाब से कॉलम के नाम, सामान्य कॉलम के नामों से कैसे मैप होते हैं

दूसरी इमेज. टाइप के हिसाब से कॉलम के नाम और सामान्य कॉलम के नाम.

टाइप के हिसाब से कॉलम के नाम की क्लास

दूसरी टेबल में, टाइप के हिसाब से कॉलम के नाम की सबसे ज़्यादा इस्तेमाल की जाने वाली क्लास दी गई हैं:

टेबल 2. टाइप के हिसाब से कॉलम के नाम की क्लास

मैपिंग क्लास डेटा का टाइप नोट
ContactsContract.CommonDataKinds.StructuredName इस डेटा लाइन से जुड़े रॉ संपर्क का नाम. रॉ संपर्क में इनमें से सिर्फ़ एक लाइन होती है.
ContactsContract.CommonDataKinds.Photo इस डेटा लाइन से जुड़े रॉ संपर्क की मुख्य फ़ोटो. रॉ संपर्क में इनमें से सिर्फ़ एक लाइन होती है.
ContactsContract.CommonDataKinds.Email इस डेटा लाइन से जुड़े रॉ संपर्क का ईमेल पता. किसी रॉ संपर्क के कई ईमेल पते हो सकते हैं.
ContactsContract.CommonDataKinds.StructuredPostal इस डेटा लाइन से जुड़े रॉ संपर्क का डाक पता. किसी रॉ संपर्क के कई डाक पते हो सकते हैं.
ContactsContract.CommonDataKinds.GroupMembership यह एक आइडेंटिफ़ायर है, जो रॉ कॉन्टैक्ट को संपर्क सूची के किसी ग्रुप से लिंक करता है. ग्रुप, खाते के टाइप और खाते के नाम की एक वैकल्पिक सुविधा है. इनके बारे में ज़्यादा जानकारी, संपर्क ग्रुप सेक्शन में दी गई है.

संपर्क

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

ध्यान दें: अगर आपने Contacts Provider में insert() वाला कोई संपर्क जोड़ने की कोशिश की, तो आपको UnsupportedOperationException अपवाद मिलेगा. अगर "सिर्फ़ पढ़ने के लिए" के तौर पर लिस्ट किए गए कॉलम को अपडेट करने की कोशिश की जाती है, तो अपडेट को अनदेखा कर दिया जाता है.

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

संपर्क सूची, संपर्क पंक्ति को उसकी रॉ संपर्क पंक्तियों से लिंक करती है. इसके लिए, वह Contacts टेबल में संपर्क पंक्ति के _ID कॉलम का इस्तेमाल करती है. कच्चे संपर्क की टेबल के CONTACT_ID कॉलम में, ContactsContract.RawContacts_ID वैल्यू होती हैं. ये वैल्यू, हर कच्चे संपर्क की लाइन से जुड़ी संपर्क लाइन के लिए होती हैं.

ContactsContract.Contacts टेबल में LOOKUP_KEY कॉलम भी होता है. यह संपर्क पंक्ति से "स्थायी" तौर पर जुड़ा होता है. क्योंकि संपर्क सूची संपर्कों को अपने-आप बनाए रखती है, इसलिए यह एग्रीगेशन या सिंक के जवाब में, संपर्क की लाइन की _ID वैल्यू बदल सकती है. ऐसा होने पर भी, कॉन्टेंट यूआरआई CONTENT_LOOKUP_URI के साथ संपर्क का LOOKUP_KEY अब भी संपर्क वाली लाइन पर ले जाएगा. इसलिए, "पसंदीदा" संपर्कों के लिंक बनाए रखने के लिए, LOOKUP_KEY का इस्तेमाल किया जा सकता है. इस कॉलम का अपना फ़ॉर्मैट है, जो _ID कॉलम के फ़ॉर्मैट से अलग है.

तीसरी इमेज में दिखाया गया है कि तीन मुख्य टेबल एक-दूसरे से कैसे जुड़ी हैं.

संपर्क की जानकारी देने वाली मुख्य टेबल

तीसरी इमेज. संपर्क, रॉ कॉन्टैक्ट, और जानकारी वाली टेबल के बीच संबंध.

अहम जानकारी: अगर आपने Google Play Store पर अपना ऐप्लिकेशन पब्लिश किया है या आपका ऐप्लिकेशन Android 10 (एपीआई लेवल 29) या इसके बाद के वर्शन पर चल रहे डिवाइस पर है, तो ध्यान रखें कि संपर्क डेटा फ़ील्ड और तरीकों का सीमित सेट अब काम नहीं करता.

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

ऊपर दिए गए डेटा फ़ील्ड को सेट करने के लिए इस्तेमाल किए जाने वाले एपीआई भी अब काम नहीं करते:

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

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

यह पुष्टि करने के लिए कि इस बदलाव से आपके ऐप्लिकेशन के फ़ंक्शन पर कोई असर नहीं पड़ा है, इन डेटा फ़ील्ड को मैन्युअल तरीके से मिटाया जा सकता है. इसके लिए, Android 4.1 (एपीआई लेवल 16) या इसके बाद के वर्शन पर चलने वाले डिवाइस पर, नीचे दी गई ADB कमांड चलाएं:

adb shell content delete \
--uri content://com.android.contacts/contacts/delete_usage

सिंक अडैप्टर से मिला डेटा

उपयोगकर्ता, संपर्कों का डेटा सीधे डिवाइस में डालते हैं. हालांकि, डेटा वेब सेवाओं से Contacts Provider में भी जाता है. यह डेटा, सिंक अडैप्टर के ज़रिए जाता है. ये अडैप्टर, डिवाइस और सेवाओं के बीच डेटा ट्रांसफ़र की प्रोसेस को अपने-आप पूरा करते हैं. सिंक अडैप्टर, सिस्टम के कंट्रोल में बैकग्राउंड में काम करते हैं. ये डेटा को मैनेज करने के लिए, ContentResolver तरीकों का इस्तेमाल करते हैं.

Android में, सिंक अडैप्टर जिस वेब सेवा के साथ काम करता है उसकी पहचान खाते के टाइप से होती है. हर सिंक अडैप्टर, एक तरह के खाते के साथ काम करता है. हालांकि, यह उस तरह के खाते के लिए कई खाता नामों के साथ काम कर सकता है. खाते के टाइप और खाते के नामों के बारे में, संपर्क जानकारी के रॉ डेटा के सोर्स सेक्शन में बताया गया है. यहां दी गई परिभाषाओं में ज़्यादा जानकारी दी गई है. साथ ही, यह बताया गया है कि खाते का टाइप और नाम, सिंक अडैप्टर और सेवाओं से कैसे जुड़ा है.

खाता टाइप
यह उस सेवा की पहचान करता है जिसमें उपयोगकर्ता ने डेटा सेव किया है. ज़्यादातर मामलों में, उपयोगकर्ता को सेवा के लिए पुष्टि करनी होती है. उदाहरण के लिए, Google Contacts एक खाता टाइप है. इसे google.com कोड से पहचाना जाता है. यह वैल्यू, AccountManager के इस्तेमाल किए गए खाते के टाइप से मेल खाती है.
खाते का नाम
यह किसी खाता टाइप के लिए, किसी खास खाते या लॉगिन की पहचान करता है. Google Contacts खाते, Google खातों की तरह ही होते हैं. इनमें ईमेल पते को खाते के नाम के तौर पर इस्तेमाल किया जाता है. अन्य सेवाएं, एक शब्द वाले उपयोगकर्ता नाम या संख्या वाले आईडी का इस्तेमाल कर सकती हैं.

खाते के टाइप अलग-अलग होने ज़रूरी नहीं हैं. कोई उपयोगकर्ता, Google Contacts के एक से ज़्यादा खाते कॉन्फ़िगर कर सकता है. साथ ही, संपर्क सूची में उनका डेटा डाउनलोड कर सकता है. ऐसा तब हो सकता है, जब उपयोगकर्ता के पास निजी खाते के लिए निजी संपर्कों का एक सेट और काम के लिए दूसरा सेट हो. खातों के नाम आम तौर पर अलग-अलग होते हैं. ये दोनों मिलकर, Contacts Provider और किसी बाहरी सेवा के बीच डेटा के फ़्लो की पहचान करते हैं.

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

चौथे फ़िगर में दिखाया गया है कि संपर्क सूची, लोगों के डेटा के फ़्लो में कैसे काम करता है. "सिंक अडैप्टर" के तौर पर मार्क किए गए बॉक्स में, हर अडैप्टर को उसके खाते के टाइप के हिसाब से लेबल किया जाता है.

लोगों के बारे में डेटा का फ़्लो

चौथी इमेज. संपर्क सूची के डेटा का फ़्लो.

ज़रूरी अनुमतियां

संपर्क सूची ऐप्लिकेशन को ये अनुमतियां मांगनी होंगी:

एक या उससे ज़्यादा टेबल का डेटा देखने का ऐक्सेस
READ_CONTACTS, AndroidManifest.xml में <uses-permission> एलिमेंट के साथ <uses-permission android:name="android.permission.READ_CONTACTS"> के तौर पर तय किया गया है.
एक या उससे ज़्यादा टेबल में डेटा लिखने का ऐक्सेस
WRITE_CONTACTS, AndroidManifest.xml में <uses-permission> एलिमेंट के साथ <uses-permission android:name="android.permission.WRITE_CONTACTS"> के तौर पर तय किया गया है.

ये अनुमतियां, उपयोगकर्ता की प्रोफ़ाइल के डेटा पर लागू नहीं होती हैं. उपयोगकर्ता की प्रोफ़ाइल और इसके लिए ज़रूरी अनुमतियों के बारे में यहां बताया गया है, उपयोगकर्ता की प्रोफ़ाइल.

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

उपयोगकर्ता की प्रोफ़ाइल

ContactsContract.Contacts टेबल में एक लाइन होती है. इसमें डिवाइस के उपयोगकर्ता का प्रोफ़ाइल डेटा होता है. इस डेटा में, उपयोगकर्ता के किसी संपर्क के बजाय डिवाइस के user के बारे में जानकारी होती है. प्रोफ़ाइल के संपर्क वाली लाइन, उन सभी सिस्टम के लिए संपर्क वाली लाइन से जुड़ी होती है जो प्रोफ़ाइल का इस्तेमाल करते हैं. हर प्रोफ़ाइल के रॉ संपर्क की लाइन में, डेटा की कई लाइनें हो सकती हैं. उपयोगकर्ता की प्रोफ़ाइल को ऐक्सेस करने के लिए कॉन्स्टेंट, ContactsContract.Profile क्लास में उपलब्ध हैं.

उपयोगकर्ता की प्रोफ़ाइल को ऐक्सेस करने के लिए, खास अनुमतियों की ज़रूरत होती है. पढ़ने और लिखने के लिए, READ_CONTACTS और WRITE_CONTACTS अनुमतियों के अलावा, उपयोगकर्ता की प्रोफ़ाइल को ऐक्सेस करने के लिए, android.Manifest.permission#READ_PROFILE और android.Manifest.permission#WRITE_PROFILE अनुमतियों की ज़रूरत होती है. ये अनुमतियां, पढ़ने और लिखने के ऐक्सेस के लिए होती हैं.

ध्यान रखें कि आपको किसी उपयोगकर्ता की प्रोफ़ाइल को संवेदनशील मानना चाहिए. android.Manifest.permission#READ_PROFILE अनुमति से, आपको डिवाइस के उपयोगकर्ता के निजी पहचान वाले डेटा को ऐक्सेस करने की अनुमति मिलती है. अपने ऐप्लिकेशन के ब्यौरे में, उपयोगकर्ता को यह ज़रूर बताएं कि आपको उपयोगकर्ता की प्रोफ़ाइल ऐक्सेस करने की अनुमतियों की ज़रूरत क्यों है.

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

Kotlin

// Sets the columns to retrieve for the user profile
projection = arrayOf(
        ContactsContract.Profile._ID,
        ContactsContract.Profile.DISPLAY_NAME_PRIMARY,
        ContactsContract.Profile.LOOKUP_KEY,
        ContactsContract.Profile.PHOTO_THUMBNAIL_URI
)

// Retrieves the profile from the Contacts Provider
profileCursor = contentResolver.query(
        ContactsContract.Profile.CONTENT_URI,
        projection,
        null,
        null,
        null
)

Java

// Sets the columns to retrieve for the user profile
projection = new String[]
    {
        Profile._ID,
        Profile.DISPLAY_NAME_PRIMARY,
        Profile.LOOKUP_KEY,
        Profile.PHOTO_THUMBNAIL_URI
    };

// Retrieves the profile from the Contacts Provider
profileCursor =
        getContentResolver().query(
                Profile.CONTENT_URI,
                projection ,
                null,
                null,
                null);

ध्यान दें: अगर आपको संपर्क जानकारी की कई लाइनें मिलती हैं और आपको यह पता लगाना है कि इनमें से कोई लाइन उपयोगकर्ता की प्रोफ़ाइल है या नहीं, तो लाइन के IS_USER_PROFILE कॉलम की जांच करें. अगर संपर्क, उपयोगकर्ता प्रोफ़ाइल है, तो इस कॉलम में "1" सेट किया जाता है.

संपर्क सूची की सेवा देने वाली कंपनी का मेटाडेटा

संपर्क सूची, ऐसे डेटा को मैनेज करती है जो रिपॉज़िटरी में मौजूद संपर्कों के डेटा की स्थिति को ट्रैक करता है. रिपॉज़िटरी के बारे में यह मेटाडेटा, अलग-अलग जगहों पर सेव किया जाता है. जैसे, Raw Contacts, Data, और Contacts टेबल की लाइनों में, ContactsContract.Settings टेबल में, और ContactsContract.SyncState टेबल में. यहां दी गई टेबल में, इन सभी मेटाडेटा के असर के बारे में बताया गया है:

तीसरी टेबल. संपर्क सूची में मौजूद मेटाडेटा

टेबल कॉलम वैल्यू मतलब
ContactsContract.RawContacts DIRTY "0" - पिछली बार सिंक करने के बाद से कोई बदलाव नहीं हुआ है. यह उन रॉ संपर्कों को मार्क करता है जिन्हें डिवाइस पर बदला गया है और जिन्हें सर्वर पर वापस सिंक करना है. जब Android ऐप्लिकेशन किसी लाइन को अपडेट करते हैं, तो Contacts Provider इस वैल्यू को अपने-आप सेट कर देता है.

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

"1" - पिछली बार सिंक करने के बाद बदलाव किया गया है. इसे सर्वर के साथ फिर से सिंक करना होगा.
ContactsContract.RawContacts VERSION इस लाइन का वर्शन नंबर. जब भी पंक्ति या उससे जुड़ा डेटा बदलता है, तो संपर्क सूची इस वैल्यू को अपने-आप बढ़ा देती है.
ContactsContract.Data DATA_VERSION इस लाइन का वर्शन नंबर. डेटा लाइन में बदलाव होने पर, संपर्क सूची इस वैल्यू को अपने-आप बढ़ा देता है.
ContactsContract.RawContacts SOURCE_ID यह स्ट्रिंग वैल्यू, उस खाते में इस रॉ संपर्क की खास पहचान करती है जिसमें इसे बनाया गया था. जब कोई सिंक अडैप्टर नया रॉ संपर्क बनाता है, तो इस कॉलम को रॉ संपर्क के लिए सर्वर के यूनीक आईडी पर सेट किया जाना चाहिए. जब कोई Android ऐप्लिकेशन नया रॉ संपर्क बनाता है, तो ऐप्लिकेशन को इस कॉलम को खाली छोड़ देना चाहिए. इससे सिंक अडैप्टर को यह सिग्नल मिलता है कि उसे सर्वर पर एक नया रॉ संपर्क बनाना चाहिए और SOURCE_ID के लिए वैल्यू लेनी चाहिए.

खास तौर पर, हर खाते के टाइप के लिए सोर्स आईडी यूनीक होना चाहिए. साथ ही, सिंक किए गए सभी खातों में यह एक जैसा होना चाहिए:

  • यूनीक: किसी खाते के हर रॉ संपर्क के लिए, उसका अपना सोर्स आईडी होना चाहिए. अगर आपने इस सेटिंग को लागू नहीं किया, तो आपको Contacts ऐप्लिकेशन में समस्याएं आएंगी. ध्यान दें कि एक ही खाते के टाइप के लिए दो रॉ कॉन्टैक्ट में एक ही सोर्स आईडी हो सकता है. उदाहरण के लिए, खाते emily.dickinson@gmail.com के रॉ संपर्क "थॉमस हिगिंसन" को, खाते emilyd@gmail.com के रॉ संपर्क "थॉमस हिगिंसन" के जैसा ही सोर्स आईडी रखने की अनुमति है.
  • स्थिर: सोर्स आईडी, रॉ संपर्क के लिए ऑनलाइन सेवा के डेटा का स्थायी हिस्सा होते हैं. उदाहरण के लिए, अगर उपयोगकर्ता ऐप्लिकेशन की सेटिंग में जाकर, Contacts Storage का डेटा मिटा देता है और फिर से सिंक करता है, तो वापस लाए गए रॉ कॉन्टैक्ट के सोर्स आईडी पहले जैसे ही होने चाहिए. अगर आपने इसे लागू नहीं किया, तो शॉर्टकट काम करना बंद कर देंगे.
ContactsContract.Groups GROUP_VISIBLE "0" - इस ग्रुप के संपर्क, Android ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) में नहीं दिखने चाहिए. यह कॉलम, उन सर्वर के साथ काम करने के लिए है जो उपयोगकर्ता को कुछ ग्रुप में संपर्क छिपाने की अनुमति देते हैं.
"1" - इस ग्रुप में मौजूद संपर्कों को ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) में दिखने की अनुमति है.
ContactsContract.Settings UNGROUPED_VISIBLE "0" - इस खाते और खाते के टाइप के लिए, ऐसे संपर्क जो किसी ग्रुप से नहीं जुड़े हैं वे Android ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) में नहीं दिखते. डिफ़ॉल्ट रूप से, अगर किसी संपर्क का कोई भी रॉ संपर्क किसी ग्रुप का सदस्य नहीं है, तो वह संपर्क नहीं दिखता (किसी रॉ संपर्क के ग्रुप का सदस्य होने की जानकारी, ContactsContract.Data टेबल में एक या उससे ज़्यादा ContactsContract.CommonDataKinds.GroupMembership लाइनों से मिलती है). खाते के टाइप और खाते के लिए, ContactsContract.Settings टेबल की लाइन में यह फ़्लैग सेट करके, उन संपर्कों को दिखने के लिए मजबूर किया जा सकता है जिनके पास ग्रुप नहीं हैं. इस फ़्लैग का इस्तेमाल, उन सर्वर से संपर्क दिखाने के लिए किया जाता है जो ग्रुप का इस्तेमाल नहीं करते.
"1" - इस खाते और खाते के टाइप के लिए, ऐसे संपर्क ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) को दिखते हैं जो किसी ग्रुप से नहीं जुड़े हैं.
ContactsContract.SyncState (सभी) इस टेबल का इस्तेमाल, सिंक अडैप्टर के मेटाडेटा को सेव करने के लिए करें. इस टेबल की मदद से, सिंक की स्थिति और सिंक से जुड़ा अन्य डेटा, डिवाइस पर लगातार सेव किया जा सकता है.

संपर्क सूची का ऐक्सेस

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

  • इकाई के बारे में क्वेरी.
  • एक साथ कई बदलाव करना.
  • इरादों के हिसाब से जानकारी पाना और उसमें बदलाव करना.
  • डेटा का रखरखाव.

सिंक अडैप्टर से बदलाव करने के बारे में ज़्यादा जानकारी, संपर्क सूची सिंक अडैप्टर सेक्शन में दी गई है.

क्वेरी करने वाली इकाइयां

क्योंकि संपर्क सूची टेबल को हैरारकी में व्यवस्थित किया जाता है, इसलिए अक्सर किसी पंक्ति और उससे जुड़ी सभी "चाइल्ड" पंक्तियों को वापस पाने के लिए, इस तरीके का इस्तेमाल करना फ़ायदेमंद होता है. उदाहरण के लिए, किसी व्यक्ति की पूरी जानकारी दिखाने के लिए, आपको किसी एक ContactsContract.Contacts लाइन की सभी ContactsContract.RawContacts लाइनें या किसी एक ContactsContract.RawContacts लाइन की सभी ContactsContract.CommonDataKinds.Email लाइनें वापस लानी पड़ सकती हैं. इसके लिए, Contacts Provider entity कंस्ट्रक्ट उपलब्ध कराता है. ये टेबल के बीच डेटाबेस जॉइन की तरह काम करते हैं.

इकाई, पैरंट टेबल और उसकी चाइल्ड टेबल के चुने गए कॉलम से बनी टेबल की तरह होती है. किसी इकाई के बारे में क्वेरी करते समय, आपको इकाई से उपलब्ध कॉलम के आधार पर प्रोजेक्शन और खोज की शर्तें देनी होती हैं. नतीजा एक Cursor होता है. इसमें हर चाइल्ड टेबल लाइन के लिए एक लाइन होती है. उदाहरण के लिए, अगर आपने किसी संपर्क के नाम के लिए ContactsContract.Contacts.Entity क्वेरी की है और उस नाम के सभी रॉ संपर्कों के लिए सभी ContactsContract.CommonDataKinds.Email पंक्तियों की क्वेरी की है, तो आपको Cursor वापस मिलेगा. इसमें हर ContactsContract.CommonDataKinds.Email पंक्ति के लिए एक पंक्ति होगी.

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

ध्यान दें: आम तौर पर, किसी इकाई में पैरंट और चाइल्ड टेबल के सभी कॉलम शामिल नहीं होते. अगर किसी ऐसे कॉलम के नाम का इस्तेमाल किया जाता है जो इकाई के लिए कॉलम के नाम वाले कॉन्स्टेंट की सूची में नहीं है, तो आपको Exception मिलेगा.

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

यह स्निपेट, "जानकारी" गतिविधि से लिया गया है:

Kotlin

...
    /*
     * Appends the entity path to the URI. In the case of the Contacts Provider, the
     * expected URI is content://com.google.contacts/#/entity (# is the ID value).
     */
    contactUri = Uri.withAppendedPath(
            contactUri,
            ContactsContract.Contacts.Entity.CONTENT_DIRECTORY
    )

    // Initializes the loader identified by LOADER_ID.
    loaderManager.initLoader(
            LOADER_ID,  // The identifier of the loader to initialize
            null,       // Arguments for the loader (in this case, none)
            this        // The context of the activity
    )

    // Creates a new cursor adapter to attach to the list view
    cursorAdapter = SimpleCursorAdapter(
            this,                       // the context of the activity
            R.layout.detail_list_item,  // the view item containing the detail widgets
            mCursor,                    // the backing cursor
            fromColumns,               // the columns in the cursor that provide the data
            toViews,                   // the views in the view item that display the data
            0)                          // flags

    // Sets the ListView's backing adapter.
    rawContactList.adapter = cursorAdapter
...
override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> {
    /*
     * Sets the columns to retrieve.
     * RAW_CONTACT_ID is included to identify the raw contact associated with the data row.
     * DATA1 contains the first column in the data row (usually the most important one).
     * MIMETYPE indicates the type of data in the data row.
     */
    val projection: Array<String> = arrayOf(
            ContactsContract.Contacts.Entity.RAW_CONTACT_ID,
            ContactsContract.Contacts.Entity.DATA1,
            ContactsContract.Contacts.Entity.MIMETYPE
    )

    /*
     * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw
     * contact collated together.
     */
    val sortOrder = "${ContactsContract.Contacts.Entity.RAW_CONTACT_ID} ASC"

    /*
     * Returns a new CursorLoader. The arguments are similar to
     * ContentResolver.query(), except for the Context argument, which supplies the location of
     * the ContentResolver to use.
     */
    return CursorLoader(
            applicationContext, // The activity's context
            contactUri,        // The entity content URI for a single contact
            projection,         // The columns to retrieve
            null,               // Retrieve all the raw contacts and their data rows.
            null,               //
            sortOrder           // Sort by the raw contact ID.
    )
}

Java

...
    /*
     * Appends the entity path to the URI. In the case of the Contacts Provider, the
     * expected URI is content://com.google.contacts/#/entity (# is the ID value).
     */
    contactUri = Uri.withAppendedPath(
            contactUri,
            ContactsContract.Contacts.Entity.CONTENT_DIRECTORY);

    // Initializes the loader identified by LOADER_ID.
    getLoaderManager().initLoader(
            LOADER_ID,  // The identifier of the loader to initialize
            null,       // Arguments for the loader (in this case, none)
            this);      // The context of the activity

    // Creates a new cursor adapter to attach to the list view
    cursorAdapter = new SimpleCursorAdapter(
            this,                        // the context of the activity
            R.layout.detail_list_item,   // the view item containing the detail widgets
            mCursor,                     // the backing cursor
            fromColumns,                // the columns in the cursor that provide the data
            toViews,                    // the views in the view item that display the data
            0);                          // flags

    // Sets the ListView's backing adapter.
    rawContactList.setAdapter(cursorAdapter);
...
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {

    /*
     * Sets the columns to retrieve.
     * RAW_CONTACT_ID is included to identify the raw contact associated with the data row.
     * DATA1 contains the first column in the data row (usually the most important one).
     * MIMETYPE indicates the type of data in the data row.
     */
    String[] projection =
        {
            ContactsContract.Contacts.Entity.RAW_CONTACT_ID,
            ContactsContract.Contacts.Entity.DATA1,
            ContactsContract.Contacts.Entity.MIMETYPE
        };

    /*
     * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw
     * contact collated together.
     */
    String sortOrder =
            ContactsContract.Contacts.Entity.RAW_CONTACT_ID +
            " ASC";

    /*
     * Returns a new CursorLoader. The arguments are similar to
     * ContentResolver.query(), except for the Context argument, which supplies the location of
     * the ContentResolver to use.
     */
    return new CursorLoader(
            getApplicationContext(),  // The activity's context
            contactUri,              // The entity content URI for a single contact
            projection,               // The columns to retrieve
            null,                     // Retrieve all the raw contacts and their data rows.
            null,                     //
            sortOrder);               // Sort by the raw contact ID.
}

डेटा लोड होने के बाद, LoaderManager, onLoadFinished() को कॉलबैक शुरू करता है. इस तरीके के लिए, आने वाले आर्ग्युमेंट में से एक Cursor है. इसमें क्वेरी के नतीजे शामिल होते हैं. अपने ऐप्लिकेशन में, इस Cursor से डेटा पाया जा सकता है, ताकि उसे दिखाया जा सके या उस पर आगे काम किया जा सके.

एक साथ कई बदलाव करने की सुविधा

जब भी हो सके, आपको संपर्क सूची में डेटा डालना, अपडेट करना, और मिटाना चाहिए. इसके लिए, "बैच मोड" का इस्तेमाल करें. इसके लिए, ArrayList के ContentProviderOperation ऑब्जेक्ट बनाएं और applyBatch() को कॉल करें. ऐसा इसलिए होता है, क्योंकि Contacts Provider, applyBatch() में सभी कार्रवाइयां एक ही लेन-देन में करता है. इसलिए, आपके बदलाव कभी भी संपर्कों के डेटा स्टोर में अलग-अलग स्थिति में नहीं दिखेंगे. बैच में बदलाव करने की सुविधा की मदद से, एक साथ रॉ संपर्क और उसके बारे में जानकारी वाला डेटा भी डाला जा सकता है.

ध्यान दें: किसी एक रॉ संपर्क में बदलाव करने के लिए, अपने ऐप्लिकेशन में बदलाव करने के बजाय, डिवाइस के Contacts ऐप्लिकेशन को इंटेंट भेजें. ऐसा करने के बारे में ज़्यादा जानकारी, इंटेंट की मदद से डेटा पाना और उसमें बदलाव करना सेक्शन में दी गई है.

ईल्ड पॉइंट

बदलाव के ऐसे बैच में कई कार्रवाइयां शामिल हो सकती हैं जो अन्य प्रोसेस को ब्लॉक कर सकती हैं. इससे उपयोगकर्ता को खराब अनुभव मिल सकता है. आपको जितने भी बदलाव करने हैं उन्हें कम से कम अलग-अलग सूचियों में व्यवस्थित करने के लिए, एक या उससे ज़्यादा कार्रवाइयों के लिए यील्ड पॉइंट सेट करें. इससे सिस्टम को ब्लॉक होने से भी बचाया जा सकेगा. यील्ड पॉइंट एक ContentProviderOperation ऑब्जेक्ट होता है, जिसकी isYieldAllowed() वैल्यू true पर सेट होती है. जब Contacts Provider को यिल्ड पॉइंट मिलता है, तो वह अपना काम रोक देता है, ताकि अन्य प्रोसेस चल सकें. साथ ही, वह मौजूदा लेन-देन को बंद कर देता है. जब प्रोवाइडर फिर से शुरू होता है, तो वह ArrayList में अगले ऑपरेशन को जारी रखता है और एक नया ट्रांजै़क्शन शुरू करता है.

पॉइंट जनरेट करने वाले फ़ंक्शन की वजह से, applyBatch() को किए गए हर कॉल पर एक से ज़्यादा लेन-देन होते हैं. इस वजह से, आपको मिलती-जुलती लाइनों के सेट के लिए, आखिरी ऑपरेशन के लिए यील्ड पॉइंट सेट करना चाहिए. उदाहरण के लिए, आपको ऐसे सेट में आखिरी ऑपरेशन के लिए यील्ड पॉइंट सेट करना चाहिए जो रॉ संपर्क वाली पंक्तियों और उनसे जुड़ी डेटा पंक्तियों को जोड़ता है. इसके अलावा, आपको किसी एक संपर्क से जुड़ी पंक्तियों के सेट के लिए आखिरी ऑपरेशन के लिए भी यील्ड पॉइंट सेट करना चाहिए.

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

बदलाव के बैक रेफ़रंस

जब आपको नई रॉ संपर्क पंक्ति और उससे जुड़ी डेटा पंक्तियों को ContentProviderOperation ऑब्जेक्ट के सेट के तौर पर डालना होता है, तो आपको डेटा पंक्तियों को रॉ संपर्क पंक्ति से लिंक करना होता है. इसके लिए, रॉ संपर्क की _ID वैल्यू को RAW_CONTACT_ID वैल्यू के तौर पर डालें. हालांकि, डेटा लाइन के लिए ContentProviderOperation बनाते समय, यह वैल्यू उपलब्ध नहीं होती. ऐसा इसलिए, क्योंकि आपने अब तक संपर्क की रॉ लाइन के लिए ContentProviderOperation लागू नहीं किया है. इस समस्या को हल करने के लिए, ContentProviderOperation.Builder क्लास में withValueBackReference() तरीका है. इस तरीके से, पिछले ऑपरेशन के नतीजे वाले कॉलम को डाला या बदला जा सकता है.

withValueBackReference() मेथड में दो तर्क होते हैं:

key
यह की-वैल्यू पेयर की कुंजी है. इस आर्ग्युमेंट की वैल्यू, उस टेबल में मौजूद किसी कॉलम का नाम होना चाहिए जिसमें बदलाव किया जा रहा है.
previousResult
यह applyBatch() से मिले ContentProviderResult ऑब्जेक्ट के ऐरे में मौजूद किसी वैल्यू का 0 से शुरू होने वाला इंडेक्स होता है. बैच ऑपरेशन लागू होने पर, हर ऑपरेशन का नतीजा, नतीजों के इंटरमीडिएट ऐरे में सेव हो जाता है. previousResult वैल्यू, इन नतीजों में से किसी एक का इंडेक्स होती है. इसे key वैल्यू के साथ सेव किया जाता है. इससे आपको नई रॉ संपर्क रिकॉर्ड डालने और उसकी _ID वैल्यू वापस पाने की अनुमति मिलती है. इसके बाद, ContactsContract.Data लाइन जोड़ते समय, वैल्यू का "बैक रेफ़रंस" बनाया जा सकता है.

जब पहली बार applyBatch() को कॉल किया जाता है, तब पूरी नतीजे वाली कैटगरी बनाई जाती है. इसका साइज़, आपके दिए गए ContentProviderOperation ऑब्जेक्ट के ArrayList के साइज़ के बराबर होता है. हालांकि, नतीजे के तौर पर मिली कलेक्शन में मौजूद सभी एलिमेंट को null पर सेट किया जाता है. साथ ही, अगर आपने किसी ऐसी कार्रवाई के नतीजे का बैक रेफ़रंस देने की कोशिश की है जिसे अभी तक लागू नहीं किया गया है, तो withValueBackReference(), Exception दिखाता है.

यहां दिए गए स्निपेट में, बैच में नया रॉ संपर्क और डेटा डालने का तरीका बताया गया है. इनमें ऐसा कोड शामिल होता है जो यील्ड पॉइंट सेट करता है और बैक रेफ़रंस का इस्तेमाल करता है.

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

Kotlin

// Creates a contact entry from the current UI values, using the currently-selected account.
private fun createContactEntry() {
    /*
     * Gets values from the UI
     */
    val name = contactNameEditText.text.toString()
    val phone = contactPhoneEditText.text.toString()
    val email = contactEmailEditText.text.toString()

    val phoneType: String = contactPhoneTypes[mContactPhoneTypeSpinner.selectedItemPosition]

    val emailType: String = contactEmailTypes[mContactEmailTypeSpinner.selectedItemPosition]

Java

// Creates a contact entry from the current UI values, using the currently-selected account.
protected void createContactEntry() {
    /*
     * Gets values from the UI
     */
    String name = contactNameEditText.getText().toString();
    String phone = contactPhoneEditText.getText().toString();
    String email = contactEmailEditText.getText().toString();

    int phoneType = contactPhoneTypes.get(
            contactPhoneTypeSpinner.getSelectedItemPosition());

    int emailType = contactEmailTypes.get(
            contactEmailTypeSpinner.getSelectedItemPosition());

अगला स्निपेट, ContactsContract.RawContacts टेबल में रॉ संपर्क वाली लाइन डालने के लिए एक ऑपरेशन बनाता है:

Kotlin

    /*
     * Prepares the batch operation for inserting a new raw contact and its data. Even if
     * the Contacts Provider does not have any data for this person, you can't add a Contact,
     * only a raw contact. The Contacts Provider will then add a Contact automatically.
     */

    // Creates a new array of ContentProviderOperation objects.
    val ops = arrayListOf<ContentProviderOperation>()

    /*
     * Creates a new raw contact with its account type (server type) and account name
     * (user's account). Remember that the display name is not stored in this row, but in a
     * StructuredName data row. No other data is required.
     */
    var op: ContentProviderOperation.Builder =
            ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                    .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.name)
                    .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.type)

    // Builds the operation and adds it to the array of operations
    ops.add(op.build())

Java

    /*
     * Prepares the batch operation for inserting a new raw contact and its data. Even if
     * the Contacts Provider does not have any data for this person, you can't add a Contact,
     * only a raw contact. The Contacts Provider will then add a Contact automatically.
     */

     // Creates a new array of ContentProviderOperation objects.
    ArrayList<ContentProviderOperation> ops =
            new ArrayList<ContentProviderOperation>();

    /*
     * Creates a new raw contact with its account type (server type) and account name
     * (user's account). Remember that the display name is not stored in this row, but in a
     * StructuredName data row. No other data is required.
     */
    ContentProviderOperation.Builder op =
            ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
            .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType())
            .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName());

    // Builds the operation and adds it to the array of operations
    ops.add(op.build());

इसके बाद, कोड डिसप्ले नेम, फ़ोन, और ईमेल पते की पंक्तियों के लिए डेटा लाइनें बनाता है.

हर ऑपरेशन बिल्डर ऑब्जेक्ट, RAW_CONTACT_ID पाने के लिए withValueBackReference() का इस्तेमाल करता है. रेफ़रंस पॉइंट, पहले ऑपरेशन से ContentProviderResult ऑब्जेक्ट पर वापस जाता है. इससे रॉ संपर्क वाली लाइन जुड़ जाती है और उसकी नई _ID वैल्यू दिखती है. इस वजह से, हर डेटा लाइन अपने RAW_CONTACT_ID के हिसाब से, उस नई ContactsContract.RawContacts लाइन से अपने-आप लिंक हो जाती है जिससे वह जुड़ी होती है.

ईमेल वाली लाइन जोड़ने वाले ContentProviderOperation.Builder ऑब्जेक्ट को withYieldAllowed() के तौर पर फ़्लैग किया गया है. इससे यील्ड पॉइंट सेट होता है:

Kotlin

    // Creates the display name for the new raw contact, as a StructuredName data row.
    op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            /*
             * withValueBackReference sets the value of the first argument to the value of
             * the ContentProviderResult indexed by the second argument. In this particular
             * call, the raw contact ID column of the StructuredName data row is set to the
             * value of the result returned by the first operation, which is the one that
             * actually adds the raw contact row.
             */
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

            // Sets the data row's MIME type to StructuredName
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)

            // Sets the data row's display name to the name in the UI.
            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name)

    // Builds the operation and adds it to the array of operations
    ops.add(op.build())

    // Inserts the specified phone number and type as a Phone data row
    op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            /*
             * Sets the value of the raw contact id column to the new raw contact ID returned
             * by the first operation in the batch.
             */
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

            // Sets the data row's MIME type to Phone
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)

            // Sets the phone number and type
            .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
            .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType)

    // Builds the operation and adds it to the array of operations
    ops.add(op.build())

    // Inserts the specified email and type as a Phone data row
    op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            /*
             * Sets the value of the raw contact id column to the new raw contact ID returned
             * by the first operation in the batch.
             */
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

            // Sets the data row's MIME type to Email
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)

            // Sets the email address and type
            .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email)
            .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType)

    /*
     * Demonstrates a yield point. At the end of this insert, the batch operation's thread
     * will yield priority to other threads. Use after every set of operations that affect a
     * single contact, to avoid degrading performance.
     */
    op.withYieldAllowed(true)

    // Builds the operation and adds it to the array of operations
    ops.add(op.build())

Java

    // Creates the display name for the new raw contact, as a StructuredName data row.
    op =
            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            /*
             * withValueBackReference sets the value of the first argument to the value of
             * the ContentProviderResult indexed by the second argument. In this particular
             * call, the raw contact ID column of the StructuredName data row is set to the
             * value of the result returned by the first operation, which is the one that
             * actually adds the raw contact row.
             */
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

            // Sets the data row's MIME type to StructuredName
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)

            // Sets the data row's display name to the name in the UI.
            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);

    // Builds the operation and adds it to the array of operations
    ops.add(op.build());

    // Inserts the specified phone number and type as a Phone data row
    op =
            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            /*
             * Sets the value of the raw contact id column to the new raw contact ID returned
             * by the first operation in the batch.
             */
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

            // Sets the data row's MIME type to Phone
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)

            // Sets the phone number and type
            .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
            .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType);

    // Builds the operation and adds it to the array of operations
    ops.add(op.build());

    // Inserts the specified email and type as a Phone data row
    op =
            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            /*
             * Sets the value of the raw contact id column to the new raw contact ID returned
             * by the first operation in the batch.
             */
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

            // Sets the data row's MIME type to Email
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)

            // Sets the email address and type
            .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email)
            .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType);

    /*
     * Demonstrates a yield point. At the end of this insert, the batch operation's thread
     * will yield priority to other threads. Use after every set of operations that affect a
     * single contact, to avoid degrading performance.
     */
    op.withYieldAllowed(true);

    // Builds the operation and adds it to the array of operations
    ops.add(op.build());

आखिरी स्निपेट में, applyBatch() को कॉल करने का तरीका दिखाया गया है. यह नया रॉ संपर्क और डेटा लाइनें डालता है.

Kotlin

    // Ask the Contacts Provider to create a new contact
    Log.d(TAG, "Selected account: ${mSelectedAccount.name} (${mSelectedAccount.type})")
    Log.d(TAG, "Creating contact: $name")

    /*
     * Applies the array of ContentProviderOperation objects in batch. The results are
     * discarded.
     */
    try {
        contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)
    } catch (e: Exception) {
        // Display a warning
        val txt: String = getString(R.string.contactCreationFailure)
        Toast.makeText(applicationContext, txt, Toast.LENGTH_SHORT).show()

        // Log exception
        Log.e(TAG, "Exception encountered while inserting contact: $e")
    }
}

Java

    // Ask the Contacts Provider to create a new contact
    Log.d(TAG,"Selected account: " + selectedAccount.getName() + " (" +
            selectedAccount.getType() + ")");
    Log.d(TAG,"Creating contact: " + name);

    /*
     * Applies the array of ContentProviderOperation objects in batch. The results are
     * discarded.
     */
    try {

            getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
    } catch (Exception e) {

            // Display a warning
            Context ctx = getApplicationContext();

            CharSequence txt = getString(R.string.contactCreationFailure);
            int duration = Toast.LENGTH_SHORT;
            Toast toast = Toast.makeText(ctx, txt, duration);
            toast.show();

            // Log exception
            Log.e(TAG, "Exception encountered while inserting contact: " + e);
    }
}

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

ऑप्टिमिस्टिक कंकरेंसी कंट्रोल, मोबाइल डिवाइस के लिए फ़ायदेमंद होता है. ऐसा इसलिए, क्योंकि मोबाइल डिवाइस पर एक समय में सिर्फ़ एक उपयोगकर्ता होता है. साथ ही, डेटा रिपॉज़िटरी को एक साथ ऐक्सेस करने की घटनाएं कम होती हैं. लॉक करने की सुविधा का इस्तेमाल नहीं किया जाता है, इसलिए लॉक सेट करने या अन्य लेन-देन के लॉक रिलीज़ होने का इंतज़ार करने में समय बर्बाद नहीं होता.

किसी एक ContactsContract.RawContacts लाइन को अपडेट करते समय, ऑप्टिमिस्टिक कंकरेंसी कंट्रोल का इस्तेमाल करने के लिए, यह तरीका अपनाएं:

  1. संपर्क की जानकारी के साथ-साथ, VERSION कॉलम में मौजूद डेटा भी वापस पाएं.
  2. newAssertQuery(Uri) तरीके का इस्तेमाल करके, किसी शर्त को लागू करने के लिए सही ContentProviderOperation.Builder ऑब्जेक्ट बनाएं. कॉन्टेंट यूआरआई के लिए, RawContacts.CONTENT_URI का इस्तेमाल करें. इसमें रॉ कॉन्टैक्ट का _ID जोड़ा गया हो.
  3. ContentProviderOperation.Builder ऑब्जेक्ट के लिए, कॉल करें withValue(), ताकि VERSION कॉलम की तुलना अभी-अभी वापस पाए गए वर्शन नंबर से की जा सके.
  4. उसी ContentProviderOperation.Builder के लिए, withExpectedCount() को कॉल करें, ताकि यह पक्का किया जा सके कि इस दावे से सिर्फ़ एक लाइन की जांच की गई है.
  5. ContentProviderOperation ऑब्जेक्ट बनाने के लिए, build() को कॉल करें. इसके बाद, इस ऑब्जेक्ट को ArrayList में पहला ऑब्जेक्ट के तौर पर जोड़ें. इसे applyBatch() को पास किया जाता है.
  6. बैच लेन-देन लागू करें.

अगर आपने रॉ संपर्क की लाइन को पढ़ा है और उसके बाद किसी अन्य ऑपरेशन से उसे अपडेट किया गया है, तो "assert" ContentProviderOperation काम नहीं करेगा. साथ ही, ऑपरेशन का पूरा बैच वापस ले लिया जाएगा. इसके बाद, बैच को फिर से प्रोसेस करने का विकल्प चुना जा सकता है या कोई अन्य कार्रवाई की जा सकती है.

यहाँ दिए गए स्निपेट में, CursorLoader का इस्तेमाल करके किसी एक रॉ संपर्क के लिए क्वेरी करने के बाद, "assert" ContentProviderOperation बनाने का तरीका बताया गया है:

Kotlin

/*
 * The application uses CursorLoader to query the raw contacts table. The system calls this method
 * when the load is finished.
 */
override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) {
    // Gets the raw contact's _ID and VERSION values
    rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID))
    mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION))
}

...

// Sets up a Uri for the assert operation
val rawContactUri: Uri = ContentUris.withAppendedId(
        ContactsContract.RawContacts.CONTENT_URI,
        rawContactID
)

// Creates a builder for the assert operation
val assertOp: ContentProviderOperation.Builder =
        ContentProviderOperation.newAssertQuery(rawContactUri).apply {
            // Adds the assertions to the assert operation: checks the version
            withValue(SyncColumns.VERSION, mVersion)

            // and count of rows tested
            withExpectedCount(1)
        }

// Creates an ArrayList to hold the ContentProviderOperation objects
val ops = arrayListOf<ContentProviderOperation>()

ops.add(assertOp.build())

// You would add the rest of your batch operations to "ops" here

...

// Applies the batch. If the assert fails, an Exception is thrown
try {
    val results: Array<ContentProviderResult> = contentResolver.applyBatch(AUTHORITY, ops)
} catch (e: OperationApplicationException) {
    // Actions you want to take if the assert operation fails go here
}

Java

/*
 * The application uses CursorLoader to query the raw contacts table. The system calls this method
 * when the load is finished.
 */
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {

    // Gets the raw contact's _ID and VERSION values
    rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
    mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION));
}

...

// Sets up a Uri for the assert operation
Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactID);

// Creates a builder for the assert operation
ContentProviderOperation.Builder assertOp = ContentProviderOperation.newAssertQuery(rawContactUri);

// Adds the assertions to the assert operation: checks the version and count of rows tested
assertOp.withValue(SyncColumns.VERSION, mVersion);
assertOp.withExpectedCount(1);

// Creates an ArrayList to hold the ContentProviderOperation objects
ArrayList ops = new ArrayList<ContentProviderOperation>;

ops.add(assertOp.build());

// You would add the rest of your batch operations to "ops" here

...

// Applies the batch. If the assert fails, an Exception is thrown
try
    {
        ContentProviderResult[] results =
                getContentResolver().applyBatch(AUTHORITY, ops);

    } catch (OperationApplicationException e) {

        // Actions you want to take if the assert operation fails go here
    }

इंटेंट के साथ डेटा वापस पाना और उसमें बदलाव करना

डिवाइस के संपर्क ऐप्लिकेशन को इंटेंट भेजने से, संपर्क सूची को परोक्ष रूप से ऐक्सेस किया जा सकता है. इस इंटेंट से, डिवाइस के संपर्क ऐप्लिकेशन का यूज़र इंटरफ़ेस (यूआई) खुल जाता है. इसमें उपयोगकर्ता, संपर्क से जुड़े काम कर सकते हैं. इस तरह के ऐक्सेस से, उपयोगकर्ता ये काम कर सकते हैं:

  • सूची से कोई संपर्क चुनें और उसे अपने ऐप्लिकेशन पर वापस भेजें, ताकि उस पर आगे काम किया जा सके.
  • किसी मौजूदा संपर्क के डेटा में बदलाव करें.
  • उनके किसी भी खाते के लिए, नया रॉ संपर्क डालें.
  • किसी संपर्क या संपर्कों का डेटा मिटाएं.

अगर उपयोगकर्ता डेटा डाल रहा है या अपडेट कर रहा है, तो पहले डेटा इकट्ठा करें और उसे इंटेंट के हिस्से के तौर पर भेजें.

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

किसी प्रोवाइडर को ऐक्सेस करने का अनुरोध भेजने की सामान्य प्रोसेस के बारे में ज़्यादा जानकारी, कॉन्टेंट प्रोवाइडर की बुनियादी बातें गाइड में "इंटेंट के ज़रिए डेटा का ऐक्सेस" सेक्शन में दी गई है. उपलब्ध टास्क के लिए इस्तेमाल की जाने वाली कार्रवाई, एमआईएमई टाइप, और डेटा वैल्यू की खास जानकारी टेबल 4 में दी गई है. वहीं, putExtra() के साथ इस्तेमाल की जा सकने वाली अतिरिक्त वैल्यू की जानकारी, ContactsContract.Intents.Insert के रेफ़रंस दस्तावेज़ में दी गई है:

चौथी टेबल. संपर्क सूची के इंटेंट.

टास्क कार्रवाई डेटा MIME टाइप नोट
सूची से कोई संपर्क चुनना ACTION_PICK इनमें से कोई एक:
  • Contacts.CONTENT_URI, जिसमें संपर्कों की सूची दिखती है.
  • Phone.CONTENT_URI, जो किसी रॉ संपर्क के लिए फ़ोन नंबर की सूची दिखाता है.
  • StructuredPostal.CONTENT_URI, जो किसी रॉ संपर्क के लिए डाक पतों की सूची दिखाता है.
  • Email.CONTENT_URI, जो किसी रॉ संपर्क के लिए ईमेल पतों की सूची दिखाता है.
उपयोग नहीं किया गया यह आपके दिए गए कॉन्टेंट यूआरआई टाइप के आधार पर, रॉ कॉन्टैक्ट की सूची या रॉ कॉन्टैक्ट से मिले डेटा की सूची दिखाता है.

Call startActivityForResult(), जो चुनी गई लाइन का कॉन्टेंट यूआरआई दिखाता है. यूआरआई का फ़ॉर्म, टेबल के कॉन्टेंट का यूआरआई होता है. इसमें लाइन का LOOKUP_ID जोड़ा जाता है. डिवाइस का Contacts ऐप्लिकेशन, आपकी गतिविधि के दौरान इस कॉन्टेंट यूआरआई के लिए पढ़ने और लिखने की अनुमतियां देता है. ज़्यादा जानकारी के लिए, कॉन्टेंट उपलब्ध कराने वाली कंपनी के बारे में बुनियादी जानकारी गाइड देखें.

नया रॉ संपर्क डालें Insert.ACTION लागू नहीं RawContacts.CONTENT_TYPE, रॉ संपर्क के सेट के लिए एमआईएमई टाइप. इससे डिवाइस के संपर्क ऐप्लिकेशन की संपर्क जोड़ें स्क्रीन दिखती है. आपने इंटेंट में जो अतिरिक्त वैल्यू जोड़ी हैं वे दिखती हैं. अगर इसे startActivityForResult() के साथ भेजा जाता है, तो नए जोड़े गए रॉ संपर्क का कॉन्टेंट यूआरआई, आपकी गतिविधि के onActivityResult() कॉलबैक तरीके को Intent आर्ग्युमेंट में "data" फ़ील्ड में वापस भेज दिया जाता है. वैल्यू पाने के लिए, getData() को कॉल करें.
किसी संपर्क में बदलाव करना ACTION_EDIT संपर्क के लिए CONTENT_LOOKUP_URI. एडिटर की गतिविधि से, उपयोगकर्ता इस संपर्क से जुड़े किसी भी डेटा में बदलाव कर पाएगा. Contacts.CONTENT_ITEM_TYPE, एक संपर्क. इससे संपर्क ऐप्लिकेशन में, संपर्क में बदलाव करने की स्क्रीन दिखती है. आपने इंटेंट में जो अतिरिक्त वैल्यू जोड़ी हैं वे दिखती हैं. जब उपयोगकर्ता, बदलावों को सेव करने के लिए हो गया पर क्लिक करता है, तब आपकी गतिविधि फ़ोरग्राउंड में वापस आ जाती है.
ऐसा पिकर दिखाएं जो डेटा भी जोड़ सके. ACTION_INSERT_OR_EDIT लागू नहीं CONTENT_ITEM_TYPE इस इंटेंट से, हमेशा Contacts ऐप्लिकेशन की पिकर स्क्रीन दिखती है. उपयोगकर्ता के पास, किसी संपर्क की जानकारी में बदलाव करने या नया संपर्क जोड़ने का विकल्प होता है. उपयोगकर्ता के चुने गए विकल्प के आधार पर, बदलाव करने या जोड़ने वाली स्क्रीन दिखती है. साथ ही, इंटेंट में पास किया गया अतिरिक्त डेटा दिखता है. अगर आपका ऐप्लिकेशन, ईमेल या फ़ोन नंबर जैसे संपर्क डेटा को दिखाता है, तो इस इंटेंट का इस्तेमाल करें. इससे उपयोगकर्ता, डेटा को किसी मौजूदा संपर्क में जोड़ पाएगा. संपर्क करें,

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

डिवाइस का Contacts ऐप्लिकेशन, आपको किसी रॉ संपर्क या उसके किसी डेटा को मिटाने की अनुमति नहीं देता. इसके बजाय, किसी रॉ संपर्क को मिटाने के लिए, ContentResolver.delete() या ContentProviderOperation.newDelete() का इस्तेमाल करें.

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

Kotlin

// Gets values from the UI
val name = contactNameEditText.text.toString()
val phone = contactPhoneEditText.text.toString()
val email = contactEmailEditText.text.toString()

val company = companyName.text.toString()
val jobtitle = jobTitle.text.toString()

/*
 * Demonstrates adding data rows as an array list associated with the DATA key
 */

// Defines an array list to contain the ContentValues objects for each row
val contactData = arrayListOf<ContentValues>()

/*
 * Defines the raw contact row
 */

// Sets up the row as a ContentValues object
val rawContactRow = ContentValues().apply {
    // Adds the account type and name to the row
    put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.type)
    put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.name)
}

// Adds the row to the array
contactData.add(rawContactRow)

/*
 * Sets up the phone number data row
 */

// Sets up the row as a ContentValues object
val phoneRow = ContentValues().apply {
    // Specifies the MIME type for this data row (all data rows must be marked by their type)
    put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)

    // Adds the phone number and its type to the row
    put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
}

// Adds the row to the array
contactData.add(phoneRow)

/*
 * Sets up the email data row
 */

// Sets up the row as a ContentValues object
val emailRow = ContentValues().apply {
    // Specifies the MIME type for this data row (all data rows must be marked by their type)
    put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)

    // Adds the email address and its type to the row
    put(ContactsContract.CommonDataKinds.Email.ADDRESS, email)
}

// Adds the row to the array
contactData.add(emailRow)

// Creates a new intent for sending to the device's contacts application
val insertIntent = Intent(ContactsContract.Intents.Insert.ACTION).apply {
    // Sets the MIME type to the one expected by the insertion activity
    type = ContactsContract.RawContacts.CONTENT_TYPE

    // Sets the new contact name
    putExtra(ContactsContract.Intents.Insert.NAME, name)

    // Sets the new company and job title
    putExtra(ContactsContract.Intents.Insert.COMPANY, company)
    putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle)

    /*
    * Adds the array to the intent's extras. It must be a parcelable object in order to
    * travel between processes. The device's contacts app expects its key to be
    * Intents.Insert.DATA
    */
    putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData)
}

// Send out the intent to start the device's contacts app in its add contact activity.
startActivity(insertIntent)

Java

// Gets values from the UI
String name = contactNameEditText.getText().toString();
String phone = contactPhoneEditText.getText().toString();
String email = contactEmailEditText.getText().toString();

String company = companyName.getText().toString();
String jobtitle = jobTitle.getText().toString();

// Creates a new intent for sending to the device's contacts application
Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION);

// Sets the MIME type to the one expected by the insertion activity
insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE);

// Sets the new contact name
insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name);

// Sets the new company and job title
insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company);
insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle);

/*
 * Demonstrates adding data rows as an array list associated with the DATA key
 */

// Defines an array list to contain the ContentValues objects for each row
ArrayList<ContentValues> contactData = new ArrayList<ContentValues>();


/*
 * Defines the raw contact row
 */

// Sets up the row as a ContentValues object
ContentValues rawContactRow = new ContentValues();

// Adds the account type and name to the row
rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType());
rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName());

// Adds the row to the array
contactData.add(rawContactRow);

/*
 * Sets up the phone number data row
 */

// Sets up the row as a ContentValues object
ContentValues phoneRow = new ContentValues();

// Specifies the MIME type for this data row (all data rows must be marked by their type)
phoneRow.put(
        ContactsContract.Data.MIMETYPE,
        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
);

// Adds the phone number and its type to the row
phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone);

// Adds the row to the array
contactData.add(phoneRow);

/*
 * Sets up the email data row
 */

// Sets up the row as a ContentValues object
ContentValues emailRow = new ContentValues();

// Specifies the MIME type for this data row (all data rows must be marked by their type)
emailRow.put(
        ContactsContract.Data.MIMETYPE,
        ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE
);

// Adds the email address and its type to the row
emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email);

// Adds the row to the array
contactData.add(emailRow);

/*
 * Adds the array to the intent's extras. It must be a parcelable object in order to
 * travel between processes. The device's contacts app expects its key to be
 * Intents.Insert.DATA
 */
insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData);

// Send out the intent to start the device's contacts app in its add contact activity.
startActivity(insertIntent);

डेटा का रखरखाव

संपर्कों की रिपॉज़िटरी में अहम और संवेदनशील डेटा होता है. उपयोगकर्ता चाहते हैं कि यह डेटा सही और अप-टू-डेट हो. इसलिए, Contacts Provider के पास डेटा की अखंडता के लिए अच्छी तरह से तय किए गए नियम होते हैं. संपर्कों के डेटा में बदलाव करते समय, इन नियमों का पालन करना आपकी ज़िम्मेदारी है. यहाँ कुछ ज़रूरी नियम दिए गए हैं:

जोड़ी गई हर ContactsContract.RawContacts लाइन के लिए, हमेशा एक ContactsContract.CommonDataKinds.StructuredName लाइन जोड़ें.
ContactsContract.Data टेबल में ContactsContract.CommonDataKinds.StructuredName लाइन के बिना ContactsContract.RawContacts लाइन होने पर, एग्रीगेशन के दौरान समस्याएं आ सकती हैं.
हमेशा नई ContactsContract.Data लाइनों को उनकी पैरंट ContactsContract.RawContacts लाइन से लिंक करें.
ContactsContract.Data पंक्ति को ContactsContract.RawContacts से लिंक न करने पर, वह डिवाइस के संपर्क ऐप्लिकेशन में नहीं दिखेगी. इससे सिंक अडैप्टर में समस्याएं आ सकती हैं.
सिर्फ़ उन रॉ संपर्क के डेटा में बदलाव करें जिनका मालिकाना हक आपके पास है.
ध्यान रखें कि संपर्क सूची, आम तौर पर अलग-अलग तरह के खातों/ऑनलाइन सेवाओं से डेटा मैनेज करती है. आपको यह पक्का करना होगा कि आपका ऐप्लिकेशन, सिर्फ़ उन लाइनों के डेटा में बदलाव करे या उन्हें मिटाए जो आपकी हैं. साथ ही, वह सिर्फ़ ऐसे खाते के टाइप और नाम का डेटा डाले जिसे आपने कंट्रोल किया है.
अथॉरिटी, कॉन्टेंट यूआरआई, यूआरआई पाथ, कॉलम के नाम, MIME टाइप, और TYPE वैल्यू के लिए, ContactsContract और इसकी सबक्लास में तय किए गए कॉन्स्टेंट का हमेशा इस्तेमाल करें.
इन कॉन्स्टेंट का इस्तेमाल करने से, गड़बड़ियों से बचा जा सकता है. अगर कोई कॉन्स्टेंट बंद कर दिया गया है, तो आपको कंपाइलर की चेतावनियों के साथ इसकी सूचना भी दी जाएगी.

कस्टम डेटा लाइनें

अपने कस्टम MIME टाइप बनाकर और उनका इस्तेमाल करके, ContactsContract.Data टेबल में अपनी डेटा लाइनें डाली जा सकती हैं. साथ ही, उनमें बदलाव किया जा सकता है, उन्हें मिटाया जा सकता है, और वापस लाया जा सकता है. आपकी लाइनों में, ContactsContract.DataColumns में तय किए गए कॉलम का इस्तेमाल किया जा सकता है. हालांकि, आपके पास टाइप के हिसाब से कॉलम के नामों को डिफ़ॉल्ट कॉलम के नामों से मैप करने का विकल्प होता है. डिवाइस के संपर्क ऐप्लिकेशन में, आपकी लाइनों का डेटा दिखता है. हालांकि, इसे न तो बदला जा सकता है और न ही मिटाया जा सकता है. साथ ही, उपयोगकर्ता इसमें कोई और डेटा नहीं जोड़ सकते. अगर आपको उपयोगकर्ताओं को कस्टम डेटा की पंक्तियों में बदलाव करने की अनुमति देनी है, तो आपको अपने ऐप्लिकेशन में एडिटर गतिविधि की सुविधा देनी होगी.

अपने कस्टम डेटा को दिखाने के लिए, contacts.xml फ़ाइल उपलब्ध कराएं. इसमें <ContactsAccountType> एलिमेंट और उसके एक या उससे ज़्यादा <ContactsDataKind> चाइल्ड एलिमेंट शामिल होने चाहिए. इस बारे में ज़्यादा जानकारी, <ContactsDataKind> element सेक्शन में दी गई है.

कस्टम MIME टाइप के बारे में ज़्यादा जानने के लिए, कॉन्टेंट प्रोवाइडर बनाना गाइड पढ़ें.

संपर्क सूची के सिंक अडैप्टर

संपर्क सूची देने वाले इस ऐप्लिकेशन को खास तौर पर, किसी डिवाइस और ऑनलाइन सेवा के बीच संपर्कों के डेटा को सिंक करने के लिए डिज़ाइन किया गया है. इससे लोगों को मौजूदा डेटा को नए डिवाइस पर डाउनलोड करने और मौजूदा डेटा को नए खाते में अपलोड करने की सुविधा मिलती है. सिंक करने की सुविधा से यह भी पक्का होता है कि उपयोगकर्ताओं के पास हमेशा नया डेटा उपलब्ध हो. भले ही, डेटा में बदलाव किसी भी सोर्स से किया गया हो. सिंक करने का एक और फ़ायदा यह है कि इससे डिवाइस के नेटवर्क से कनेक्ट न होने पर भी, संपर्कों का डेटा उपलब्ध रहता है.

सिंक करने की सुविधा को कई तरीकों से लागू किया जा सकता है. हालांकि, Android सिस्टम एक प्लग-इन सिंक्रनाइज़ेशन फ़्रेमवर्क उपलब्ध कराता है. यह फ़्रेमवर्क इन टास्क को अपने-आप पूरा करता है:

  • नेटवर्क की उपलब्धता की जांच की जा रही है.
  • उपयोगकर्ता की प्राथमिकताओं के आधार पर, सिंक करने की प्रोसेस को शेड्यूल और पूरा करना.
  • सिंक करने की उन प्रोसेस को फिर से शुरू करना जो रुक गई हैं.

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

सिंक अडैप्टर क्लास और फ़ाइलें

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

ध्यान दें: सिंक अडैप्टर की पहचान के लिए खाते के टाइप का इस्तेमाल करने से, सिस्टम को एक ही संगठन की अलग-अलग सेवाओं को ऐक्सेस करने वाले सिंक अडैप्टर का पता लगाने और उन्हें एक साथ ग्रुप करने की अनुमति मिलती है. उदाहरण के लिए, Google की ऑनलाइन सेवाओं के लिए सिंक अडैप्टर में एक ही तरह का खाता com.google होता है. जब उपयोगकर्ता अपने डिवाइसों में कोई Google खाता जोड़ते हैं, तो Google की सेवाओं के लिए इंस्टॉल किए गए सभी सिंक अडैप्टर एक साथ दिखते हैं. सूची में शामिल हर सिंक अडैप्टर, डिवाइस पर मौजूद किसी दूसरे कॉन्टेंट प्रोवाइडर के साथ सिंक होता है.

ज़्यादातर सेवाओं के लिए, उपयोगकर्ताओं को डेटा ऐक्सेस करने से पहले अपनी पहचान की पुष्टि करनी होती है. इसलिए, Android सिस्टम एक ऐसा ऑथेंटिकेशन फ़्रेमवर्क उपलब्ध कराता है जो सिंक अडैप्टर फ़्रेमवर्क जैसा ही होता है. साथ ही, इसका इस्तेमाल अक्सर सिंक अडैप्टर फ़्रेमवर्क के साथ किया जाता है. पुष्टि करने वाला फ़्रेमवर्क, प्लग-इन ऑथेंटिकेटर का इस्तेमाल करता है. ये AbstractAccountAuthenticator की सबक्लास होती हैं. पुष्टि करने वाला ऐप्लिकेशन, इन चरणों में उपयोगकर्ता की पहचान की पुष्टि करता है:

  1. यह कुकी, उपयोगकर्ता का नाम, पासवर्ड या इसी तरह की जानकारी (उपयोगकर्ता के क्रेडेंशियल) इकट्ठा करती है.
  2. यह कुकी, सेवा को क्रेडेंशियल भेजती है
  3. यह कुकी, सेवा के जवाब की जांच करती है.

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

पुष्टि करना ज़रूरी नहीं है, लेकिन ज़्यादातर संपर्क सेवाएं इसका इस्तेमाल करती हैं. हालांकि, पुष्टि करने के लिए Android Authentication Framework का इस्तेमाल करना ज़रूरी नहीं है.

सिंक अडैप्टर लागू करना

संपर्क सूची के लिए सिंक अडैप्टर लागू करने के लिए, आपको एक Android ऐप्लिकेशन बनाना होगा. इसमें ये चीज़ें शामिल होनी चाहिए:

यह Service कॉम्पोनेंट, सिस्टम से मिले उन अनुरोधों का जवाब देता है जिनमें सिंक अडैप्टर से बाइंड करने के लिए कहा गया हो.
जब सिस्टम को सिंक करने की प्रोसेस शुरू करनी होती है, तब वह सेवा के onBind() तरीके को कॉल करता है, ताकि सिंक अडैप्टर के लिए IBinder मिल सके. इससे सिस्टम, अडैप्टर के तरीकों को क्रॉस-प्रोसेस कॉल कर सकता है.
असल सिंक अडैप्टर, जिसे AbstractThreadedSyncAdapter की कॉन्क्रीट सबक्लास के तौर पर लागू किया जाता है.
यह क्लास, सर्वर से डेटा डाउनलोड करने, डिवाइस से डेटा अपलोड करने, और टकरावों को हल करने का काम करती है. अडैप्टर का मुख्य काम, onPerformSync() तरीके से किया जाता है. इस क्लास को सिंगलटन के तौर पर इंस्टैंशिएट किया जाना चाहिए.
यह Application की सबक्लास है.
यह क्लास, सिंक अडैप्टर सिंग्लेटन के लिए फ़ैक्ट्री के तौर पर काम करती है. सिंक अडैप्टर को इंस्टैंशिएट करने के लिए, onCreate() तरीके का इस्तेमाल करें. साथ ही, सिंक अडैप्टर की सेवा के onBind() तरीके को सिंगलेटन वापस करने के लिए, स्टैटिक "getter" तरीका उपलब्ध कराएं.
ज़रूरी नहीं: यह एक Service कॉम्पोनेंट है, जो उपयोगकर्ता की पुष्टि करने के लिए सिस्टम से मिले अनुरोधों का जवाब देता है.
AccountManager इस सेवा को शुरू करता है, ताकि पुष्टि करने की प्रोसेस शुरू की जा सके. सेवा का onCreate() तरीका, पुष्टि करने वाले ऑब्जेक्ट को इंस्टैंटिएट करता है. जब सिस्टम को ऐप्लिकेशन के सिंक अडैप्टर के लिए किसी उपयोगकर्ता खाते की पुष्टि करनी होती है, तो वह सेवा के onBind() तरीके को कॉल करता है, ताकि पुष्टि करने वाले व्यक्ति के लिए IBinder मिल सके. इससे सिस्टम, पुष्टि करने वाले व्यक्ति के तरीकों के लिए क्रॉस-प्रोसेस कॉल कर पाता है..
ज़रूरी नहीं: AbstractAccountAuthenticator का एक कॉंक्रीट सबक्लास, जो पुष्टि करने के अनुरोधों को हैंडल करता है.
यह क्लास ऐसे तरीके उपलब्ध कराती है जिन्हें AccountManager, सर्वर के साथ उपयोगकर्ता के क्रेडेंशियल की पुष्टि करने के लिए लागू करता है. पुष्टि करने की प्रक्रिया की जानकारी, इस्तेमाल की जा रही सर्वर टेक्नोलॉजी के आधार पर अलग-अलग होती है. पुष्टि करने के बारे में ज़्यादा जानने के लिए, आपको अपने सर्वर सॉफ़्टवेयर के दस्तावेज़ देखने चाहिए.
एक्सएमएल फ़ाइलें, जो सिस्टम के लिए सिंक अडैप्टर और पुष्टि करने वाले टूल को तय करती हैं.
सिंक अडैप्टर और पुष्टि करने वाली सेवा के कॉम्पोनेंट, ऐप्लिकेशन मेनिफ़ेस्ट में <service> तत्वों के तौर पर परिभाषित किए जाते हैं. इनके बारे में पहले बताया जा चुका है. इन एलिमेंट में <meta-data> चाइल्ड एलिमेंट होते हैं, जो सिस्टम को खास डेटा देते हैं:
  • सिंक अडैप्टर सेवा के लिए <meta-data> एलिमेंट, res/xml/syncadapter.xml एक्सएमएल फ़ाइल की ओर इशारा करता है. बदले में, यह फ़ाइल उस वेब सेवा के लिए यूआरआई तय करती है जिसे संपर्क सूची के साथ सिंक किया जाएगा, और वेब सेवा के लिए खाते का टाइप तय करती है.
  • ज़रूरी नहीं: पुष्टि करने वाले व्यक्ति के लिए <meta-data> एलिमेंट, एक्सएमएल फ़ाइल res/xml/authenticator.xml की ओर इशारा करता है. बदले में, यह फ़ाइल उस खाते के टाइप के बारे में बताती है जिस पर पुष्टि करने वाला यह ऐप्लिकेशन काम करता है. साथ ही, यह पुष्टि करने की प्रोसेस के दौरान दिखने वाले यूज़र इंटरफ़ेस (यूआई) संसाधनों के बारे में भी बताती है. इस एलिमेंट में बताया गया खाता टाइप, सिंक अडैप्टर के लिए बताए गए खाता टाइप के जैसा होना चाहिए.

सोशल स्ट्रीम का डेटा

android.provider.ContactsContract.StreamItems और android.provider.ContactsContract.StreamItemPhotos टेबल, सोशल नेटवर्क से आने वाले डेटा को मैनेज करती हैं. सिंक अडैप्टर लिखा जा सकता है. यह अडैप्टर, आपके नेटवर्क से स्ट्रीम किए गए डेटा को इन टेबल में जोड़ता है. इसके अलावा, इन टेबल से स्ट्रीम किए गए डेटा को पढ़ा जा सकता है और उसे अपने ऐप्लिकेशन में दिखाया जा सकता है. इन दोनों कामों को एक साथ भी किया जा सकता है. इन सुविधाओं की मदद से, सोशल नेटवर्किंग की सेवाओं और ऐप्लिकेशन को Android के सोशल नेटवर्किंग अनुभव में इंटिग्रेट किया जा सकता है.

सोशल स्ट्रीम टेक्स्ट

स्ट्रीम आइटम हमेशा किसी रॉ संपर्क से जुड़े होते हैं. android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID, रॉ संपर्क के लिए _ID वैल्यू से लिंक होता है. रॉ संपर्क के खाते का टाइप और खाते का नाम भी स्ट्रीम आइटम की लाइन में सेव किया जाता है.

अपनी स्ट्रीम का डेटा इन कॉलम में सेव करें:

android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE
ज़रूरी है. इस स्ट्रीम आइटम से जुड़े रॉ संपर्क के लिए, उपयोगकर्ता के खाते का टाइप. स्ट्रीम आइटम डालते समय, इस वैल्यू को सेट करना न भूलें.
android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME
ज़रूरी है. इस स्ट्रीम आइटम से जुड़े रॉ संपर्क के लिए, उपयोगकर्ता के खाते का नाम. स्ट्रीम आइटम डालते समय, इस वैल्यू को सेट करना न भूलें.
आइडेंटिफ़ायर कॉलम
ज़रूरी है. स्ट्रीम आइटम डालते समय, आपको यहां दिए गए आइडेंटिफ़ायर कॉलम डालने होंगे:
  • android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID: यह उस संपर्क की android.provider.BaseColumns#_ID वैल्यू होती है जिससे यह स्ट्रीम आइटम जुड़ा होता है.
  • android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY: यह उस संपर्क का android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY वैल्यू है जिससे यह स्ट्रीम आइटम जुड़ा है.
  • android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID: यह उस रॉ कॉन्टैक्ट की android.provider.BaseColumns#_ID वैल्यू है जिससे यह स्ट्रीम आइटम जुड़ा है.
android.provider.ContactsContract.StreamItemsColumns#COMMENTS
ज़रूरी नहीं. यह कुकी, खास जानकारी को सेव करती है. इसे स्ट्रीम आइटम की शुरुआत में दिखाया जा सकता है.
android.provider.ContactsContract.StreamItemsColumns#TEXT
स्ट्रीम आइटम का टेक्स्ट. इसमें आइटम के सोर्स से पोस्ट किया गया कॉन्टेंट या स्ट्रीम आइटम जनरेट करने वाली किसी कार्रवाई का ब्यौरा शामिल होता है. इस कॉलम में, fromHtml() रेंडर कर सकने वाली कोई भी फ़ॉर्मैटिंग और एम्बेड की गई रिसॉर्स इमेज शामिल हो सकती हैं. सेवा देने वाली कंपनी, लंबे कॉन्टेंट को छोटा कर सकती है या उसमें से कुछ हिस्सा हटा सकती है. हालांकि, वह टैग को तोड़ने से बचने की कोशिश करेगी.
android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP
यह एक टेक्स्ट स्ट्रिंग है. इसमें स्ट्रीम आइटम को शामिल करने या अपडेट करने का समय होता है. यह समय, epoch के बाद से मिलीसेकंड के तौर पर होता है. स्ट्रीम आइटम डालने या अपडेट करने वाले ऐप्लिकेशन, इस कॉलम को बनाए रखने के लिए ज़िम्मेदार होते हैं. इसे संपर्क सूची अपने-आप बनाए नहीं रखती.

अपने स्ट्रीम आइटम की पहचान करने वाली जानकारी दिखाने के लिए, अपने ऐप्लिकेशन में मौजूद संसाधनों से लिंक करने के लिए, android.provider.ContactsContract.StreamItemsColumns#RES_ICON, android.provider.ContactsContract.StreamItemsColumns#RES_LABEL, और android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE का इस्तेमाल करें.

android.provider.ContactsContract.StreamItems टेबल में, android.provider.ContactsContract.StreamItemsColumns#SYNC1 से लेकर android.provider.ContactsContract.StreamItemsColumns#SYNC4 तक के कॉलम भी होते हैं. इनका इस्तेमाल सिर्फ़ सिंक अडैप्टर कर सकते हैं.

सोशल स्ट्रीम की फ़ोटो

android.provider.ContactsContract.StreamItemPhotos टेबल, स्ट्रीम आइटम से जुड़ी फ़ोटो सेव करती है. टेबल के android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID कॉलम में मौजूद वैल्यू, android.provider.ContactsContract.StreamItems टेबल के _ID कॉलम में मौजूद वैल्यू से लिंक होती हैं. फ़ोटो के रेफ़रंस, टेबल में इन कॉलम में सेव किए जाते हैं:

android.provider.ContactsContract.StreamItemPhotos#PHOTO कॉलम (एक BLOB).
यह फ़ोटो का बाइनरी फ़ॉर्मैट है. इसे सेव करने और दिखाने के लिए, सेवा देने वाली कंपनी ने इसका साइज़ बदला है. यह कॉलम, Contacts Provider के पिछले वर्शन के साथ काम करने की सुविधा के लिए उपलब्ध है. इसका इस्तेमाल फ़ोटो सेव करने के लिए किया जाता था. हालांकि, मौजूदा वर्शन में आपको फ़ोटो सेव करने के लिए इस कॉलम का इस्तेमाल नहीं करना चाहिए. इसके बजाय, फ़ाइल में फ़ोटो सेव करने के लिए, android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID या android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI में से किसी एक का इस्तेमाल करें. इन दोनों के बारे में यहां बताया गया है. इस कॉलम में अब फ़ोटो का थंबनेल मौजूद है. इसे पढ़ा जा सकता है.
android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID
यह रॉ संपर्क के लिए फ़ोटो का संख्यात्मक आइडेंटिफ़ायर होता है. इस वैल्यू को कॉन्स्टेंट DisplayPhoto.CONTENT_URI में जोड़ें, ताकि आपको एक फ़ोटो फ़ाइल की ओर ले जाने वाला कॉन्टेंट यूआरआई मिल सके. इसके बाद, openAssetFileDescriptor() को कॉल करें, ताकि आपको फ़ोटो फ़ाइल का हैंडल मिल सके.
android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI
यह कॉन्टेंट यूआरआई, इस लाइन में मौजूद फ़ोटो की फ़ोटो फ़ाइल की ओर सीधे तौर पर ले जाता है. फ़ोटो फ़ाइल का हैंडल पाने के लिए, इस यूआरआई के साथ openAssetFileDescriptor() को कॉल करें.

सोशल स्ट्रीम टेबल का इस्तेमाल करना

ये टेबल, संपर्क सूची में मौजूद अन्य मुख्य टेबल की तरह ही काम करती हैं. हालांकि, इनमें ये अंतर होते हैं:

  • इन टेबल को ऐक्सेस करने के लिए, अतिरिक्त अनुमतियों की ज़रूरत होती है. इनसे डेटा पढ़ने के लिए, आपके ऐप्लिकेशन के पास android.Manifest.permission#READ_SOCIAL_STREAM की अनुमति होनी चाहिए. इनमें बदलाव करने के लिए, आपके ऐप्लिकेशन के पास android.Manifest.permission#WRITE_SOCIAL_STREAM की अनुमति होनी चाहिए.
  • android.provider.ContactsContract.StreamItems टेबल के लिए, हर रॉ संपर्क के लिए सेव की गई लाइनों की संख्या सीमित होती है. यह सीमा पूरी होने के बाद, संपर्क सूची नई स्ट्रीम आइटम लाइनों के लिए जगह बनाता है. इसके लिए, वह उन लाइनों को अपने-आप मिटा देता है जिनमें सबसे पुराना android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP होता है. सीमा पाने के लिए, कॉन्टेंट यूआरआई android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI को क्वेरी जारी करें. कॉन्टेंट यूआरआई को छोड़कर, अन्य सभी आर्ग्युमेंट को null पर सेट किया जा सकता है. क्वेरी, कर्सर दिखाती है. इसमें एक लाइन होती है. साथ ही, इसमें android.provider.ContactsContract.StreamItems#MAX_ITEMS वाला एक कॉलम होता है.

android.provider.ContactsContract.StreamItems.StreamItemPhotos क्लास, android.provider.ContactsContract.StreamItemPhotos की सब-टेबल तय करती है. इसमें किसी एक स्ट्रीम आइटम के लिए फ़ोटो की लाइनें होती हैं.

सोशल स्ट्रीम के साथ इंटरैक्शन

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

  • सिंक अडैप्टर की मदद से, सोशल नेटवर्किंग सेवा को संपर्क सूची के साथ सिंक करके, किसी उपयोगकर्ता के संपर्कों की हाल की गतिविधि को वापस पाया जा सकता है. साथ ही, इसे android.provider.ContactsContract.StreamItems और android.provider.ContactsContract.StreamItemPhotos टेबल में सेव किया जा सकता है, ताकि बाद में इसका इस्तेमाल किया जा सके.
  • नियमित तौर पर सिंक करने के अलावा, उपयोगकर्ता के किसी संपर्क को चुनने पर, सिंक अडैप्टर को ट्रिगर किया जा सकता है, ताकि वह अतिरिक्त डेटा को वापस पा सके. इससे आपका सिंक अडैप्टर, संपर्क के लिए ज़्यादा रिज़ॉल्यूशन वाली फ़ोटो और स्ट्रीम के सबसे नए आइटम वापस पा सकता है.
  • डिवाइस के Contacts ऐप्लिकेशन और Contacts Provider के साथ सूचना रजिस्टर करके, संपर्क देखे जाने पर इंटेंट पाया जा सकता है. इसके बाद, अपनी सेवा से संपर्क की स्थिति अपडेट की जा सकती है. यह तरीका, सिंक अडैप्टर के साथ पूरा सिंक करने के मुकाबले ज़्यादा तेज़ हो सकता है और इसमें कम बैंडविड्थ का इस्तेमाल होता है.
  • उपयोगकर्ता, डिवाइस के संपर्क ऐप्लिकेशन में किसी संपर्क को देखते समय, उसे आपकी सोशल नेटवर्किंग सेवा में जोड़ सकते हैं. इसे "संपर्क को न्योता दें" सुविधा की मदद से चालू किया जाता है. इस सुविधा को चालू करने के लिए, आपको दो चीज़ों की ज़रूरत होती है. पहली, ऐसी ऐक्टिविटी जो आपके नेटवर्क में मौजूद किसी संपर्क को जोड़ती है. दूसरी, एक ऐसी एक्सएमएल फ़ाइल जो डिवाइस के संपर्क ऐप्लिकेशन और संपर्क सूची को आपके ऐप्लिकेशन की जानकारी देती है.

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

इस कुकी का इस्तेमाल, सोशल नेटवर्किंग व्यू को मैनेज करने के लिए रजिस्टर करने के लिए किया जाता है

जब उपयोगकर्ता ऐसे संपर्क को देखता है जिसे आपका सिंक अडैप्टर मैनेज करता है, तब सूचनाएं पाने के लिए अपने सिंक अडैप्टर को रजिस्टर करें:

  1. अपने प्रोजेक्ट की res/xml/ डायरेक्ट्री में, contacts.xml नाम की फ़ाइल बनाएं. अगर आपके पास यह फ़ाइल पहले से है, तो इस चरण को छोड़ा जा सकता है.
  2. इस फ़ाइल में, <ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"> एलिमेंट जोड़ें. अगर यह एलिमेंट पहले से मौजूद है, तो इस चरण को छोड़ा जा सकता है.
  3. अगर आपको ऐसी सेवा रजिस्टर करनी है जिसे उपयोगकर्ता के डिवाइस के संपर्क ऐप्लिकेशन में, किसी संपर्क की ज़्यादा जानकारी वाला पेज खोलने पर सूचना मिलती है, तो एलिमेंट में viewContactNotifyService="serviceclass" एट्रिब्यूट जोड़ें. यहां serviceclass, उस सेवा का पूरी तरह से क्वालिफ़ाइड क्लासनेम है जिसे डिवाइस के संपर्क ऐप्लिकेशन से इंटेंट मिलना चाहिए. सूचना देने वाली सेवा के लिए, IntentService को बढ़ाने वाली क्लास का इस्तेमाल करें, ताकि सेवा को इंटेंट मिल सकें. इनकमिंग इंटेंट में मौजूद डेटा में, उस रॉ संपर्क का कॉन्टेंट यूआरआई होता है जिस पर उपयोगकर्ता ने क्लिक किया था. सूचना देने वाली सेवा से, अपने सिंक अडैप्टर को बाइंड किया जा सकता है. इसके बाद, रॉ संपर्क के लिए डेटा अपडेट करने के लिए, उसे कॉल किया जा सकता है.

जब उपयोगकर्ता किसी स्ट्रीम आइटम या फ़ोटो या दोनों पर क्लिक करे, तब कॉल की जाने वाली गतिविधि को रजिस्टर करने के लिए:

  1. अपने प्रोजेक्ट की res/xml/ डायरेक्ट्री में, contacts.xml नाम की फ़ाइल बनाएं. अगर आपके पास यह फ़ाइल पहले से है, तो इस चरण को छोड़ा जा सकता है.
  2. इस फ़ाइल में, <ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"> एलिमेंट जोड़ें. अगर यह एलिमेंट पहले से मौजूद है, तो इस चरण को छोड़ा जा सकता है.
  3. अगर आपको डिवाइस के संपर्क ऐप्लिकेशन में स्ट्रीम आइटम पर क्लिक करने वाले उपयोगकर्ता को हैंडल करने के लिए, अपनी किसी गतिविधि को रजिस्टर करना है, तो एलिमेंट में viewStreamItemActivity="activityclass" एट्रिब्यूट जोड़ें. यहां activityclass, उस गतिविधि का पूरी तरह से क्वालिफ़ाइड क्लासनेम है जिसे डिवाइस के संपर्क ऐप्लिकेशन से इंटेंट मिलना चाहिए.
  4. अगर आपको डिवाइस के संपर्क ऐप्लिकेशन में स्ट्रीम फ़ोटो पर क्लिक करने वाले उपयोगकर्ता को हैंडल करने के लिए, अपनी किसी ऐक्टिविटी को रजिस्टर करना है, तो एलिमेंट में viewStreamItemPhotoActivity="activityclass" एट्रिब्यूट जोड़ें. यहां activityclass, उस ऐक्टिविटी का पूरा क्लासनेम है जिसे डिवाइस के संपर्क ऐप्लिकेशन से इंटेंट मिलना चाहिए.

<ContactsAccountType> एलिमेंट के बारे में ज़्यादा जानकारी, <ContactsAccountType> एलिमेंट सेक्शन में दी गई है.

आने वाले इंटेंट में, उस आइटम या फ़ोटो का कॉन्टेंट यूआरआई होता है जिस पर उपयोगकर्ता ने क्लिक किया था. टेक्स्ट आइटम और फ़ोटो के लिए अलग-अलग गतिविधियां सेट करने के लिए, एक ही फ़ाइल में दोनों एट्रिब्यूट का इस्तेमाल करें.

सोशल नेटवर्किंग सेवा के साथ इंटरैक्ट करना

उपयोगकर्ताओं को किसी संपर्क को आपकी सोशल नेटवर्किंग साइट पर न्योता देने के लिए, डिवाइस के संपर्क ऐप्लिकेशन को छोड़ने की ज़रूरत नहीं होती. इसके बजाय, डिवाइस के Contacts ऐप्लिकेशन को किसी संपर्क को आपकी किसी गतिविधि में शामिल होने का न्योता भेजने के लिए कहा जा सकता है. इसका सेट अप करने के लिए:

  1. अपने प्रोजेक्ट की res/xml/ डायरेक्ट्री में, contacts.xml नाम की फ़ाइल बनाएं. अगर आपके पास यह फ़ाइल पहले से है, तो इस चरण को छोड़ा जा सकता है.
  2. इस फ़ाइल में, <ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"> एलिमेंट जोड़ें. अगर यह एलिमेंट पहले से मौजूद है, तो इस चरण को छोड़ा जा सकता है.
  3. ये एट्रिब्यूट जोड़ें:
    • inviteContactActivity="activityclass"
    • inviteContactActionLabel="@string/invite_action_label"
    activityclass वैल्यू, उस गतिविधि का पूरी तरह क्वालिफ़ाइड क्लासनेम है जिसे इंटेंट मिलना चाहिए. invite_action_label वैल्यू एक टेक्स्ट स्ट्रिंग होती है. यह डिवाइस के संपर्क ऐप्लिकेशन में कनेक्शन जोड़ें मेन्यू में दिखती है.

ध्यान दें: ContactsSource, ContactsAccountType के लिए इस्तेमाल किया जाने वाला टैग नेम है. हालांकि, अब इसका इस्तेमाल नहीं किया जाता.

contacts.xml का रेफ़रंस

contacts.xml फ़ाइल में ऐसे एक्सएमएल एलिमेंट होते हैं जो संपर्क सूची और संपर्क ऐप्लिकेशन के साथ आपके सिंक अडैप्टर और ऐप्लिकेशन के इंटरैक्शन को कंट्रोल करते हैं. इन एलिमेंट के बारे में, यहां दिए गए सेक्शन में बताया गया है.

<ContactsAccountType> एलिमेंट

<ContactsAccountType> एलिमेंट, आपके ऐप्लिकेशन का संपर्क ऐप्लिकेशन के साथ इंटरैक्शन कंट्रोल करता है. इसका सिंटैक्स यह है:

<ContactsAccountType
        xmlns:android="http://schemas.android.com/apk/res/android"
        inviteContactActivity="activity_name"
        inviteContactActionLabel="invite_command_text"
        viewContactNotifyService="view_notify_service"
        viewGroupActivity="group_view_activity"
        viewGroupActionLabel="group_action_text"
        viewStreamItemActivity="viewstream_activity_name"
        viewStreamItemPhotoActivity="viewphotostream_activity_name">

इसमें शामिल है:

res/xml/contacts.xml

में यह जानकारी शामिल हो सकती है:

<ContactsDataKind>

ब्यौरा:

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

ध्यान दें कि <ContactsAccountType> एट्रिब्यूट के लिए, android: एट्रिब्यूट प्रीफ़िक्स का इस्तेमाल करना ज़रूरी नहीं है.

एट्रिब्यूट:

inviteContactActivity
आपके ऐप्लिकेशन में मौजूद उस गतिविधि का पूरा क्लास नेम जिसे आपको तब चालू करना है, जब उपयोगकर्ता डिवाइस के संपर्क ऐप्लिकेशन में जाकर कनेक्शन जोड़ें को चुनता है.
inviteContactActionLabel
यह एक टेक्स्ट स्ट्रिंग है. यह inviteContactActivity में बताई गई गतिविधि के लिए, कनेक्शन जोड़ें मेन्यू में दिखती है. उदाहरण के लिए, "मेरे नेटवर्क में फ़ॉलो करें" स्ट्रिंग का इस्तेमाल किया जा सकता है. इस लेबल के लिए, स्ट्रिंग रिसॉर्स आइडेंटिफ़ायर का इस्तेमाल किया जा सकता है.
viewContactNotifyService
आपके ऐप्लिकेशन में मौजूद किसी ऐसी सेवा का पूरी तरह क्वालिफ़ाइड क्लास नेम जिसे उपयोगकर्ता के संपर्क देखने पर सूचनाएं मिलनी चाहिए. यह सूचना, डिवाइस के संपर्क ऐप्लिकेशन से भेजी जाती है. इससे आपका ऐप्लिकेशन, डेटा का ज़्यादा इस्तेमाल करने वाली कार्रवाइयों को तब तक के लिए रोक सकता है, जब तक उनकी ज़रूरत न हो. उदाहरण के लिए, आपका ऐप्लिकेशन इस सूचना का जवाब दे सकता है. इसके लिए, वह संपर्क की ज़्यादा रिज़ॉल्यूशन वाली फ़ोटो और सोशल मीडिया पर की गई उसकी हाल ही की पोस्ट को पढ़ सकता है और दिखा सकता है. इस सुविधा के बारे में ज़्यादा जानकारी, सोशल स्ट्रीम इंटरैक्शन सेक्शन में दी गई है.
viewGroupActivity
आपके ऐप्लिकेशन में मौजूद किसी ऐसी गतिविधि की क्लास का पूरी तरह क्वालिफ़ाइड नाम जो ग्रुप की जानकारी दिखा सकती है. जब उपयोगकर्ता डिवाइस के Contacts ऐप्लिकेशन में ग्रुप के लेबल पर क्लिक करता है, तब इस गतिविधि के लिए यूज़र इंटरफ़ेस (यूआई) दिखता है.
viewGroupActionLabel
यह एक ऐसा लेबल है जिसे संपर्क ऐप्लिकेशन, यूज़र इंटरफ़ेस (यूआई) कंट्रोल के लिए दिखाता है. इससे उपयोगकर्ता को आपके ऐप्लिकेशन में ग्रुप देखने की अनुमति मिलती है.

इस एट्रिब्यूट के लिए, स्ट्रिंग रिसॉर्स आइडेंटिफ़ायर का इस्तेमाल किया जा सकता है.

viewStreamItemActivity
आपके ऐप्लिकेशन में मौजूद किसी ऐसी ऐक्टिविटी का पूरा क्लास नेम जिसे डिवाइस का संपर्क ऐप्लिकेशन, उपयोगकर्ता के किसी रॉ संपर्क के स्ट्रीम आइटम पर क्लिक करने पर लॉन्च करता है.
viewStreamItemPhotoActivity
आपके ऐप्लिकेशन में मौजूद किसी गतिविधि का पूरा क्लास नेम. जब उपयोगकर्ता, रॉ संपर्क के लिए स्ट्रीम आइटम में मौजूद किसी फ़ोटो पर क्लिक करता है, तब डिवाइस का संपर्क ऐप्लिकेशन इस क्लास नेम को लॉन्च करता है.

<ContactsDataKind> एलिमेंट

<ContactsDataKind> एलिमेंट, संपर्क ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) में, आपके ऐप्लिकेशन की कस्टम डेटा लाइनें दिखाने की सुविधा को कंट्रोल करता है. इसका सिंटैक्स यह है:

<ContactsDataKind
        android:mimeType="MIMEtype"
        android:icon="icon_resources"
        android:summaryColumn="column_name"
        android:detailColumn="column_name">

इसमें शामिल है:

<ContactsAccountType>

ब्यौरा:

इस एलिमेंट का इस्तेमाल करके, संपर्क ऐप्लिकेशन को कस्टम डेटा लाइन का कॉन्टेंट दिखाने के लिए कहा जा सकता है. यह कॉन्टेंट, रॉ कॉन्टैक्ट की जानकारी के तौर पर दिखाया जाता है. <ContactsAccountType> का हर <ContactsDataKind> चाइल्ड एलिमेंट, कस्टम डेटा की एक लाइन को दिखाता है. सिंक अडैप्टर, इस लाइन को ContactsContract.Data टेबल में जोड़ता है. इस्तेमाल किए गए हर कस्टम एमआईएमई टाइप के लिए, एक <ContactsDataKind> एलिमेंट जोड़ें. अगर आपके पास कस्टम डेटा की ऐसी लाइन है जिसके लिए आपको डेटा नहीं दिखाना है, तो आपको यह एलिमेंट जोड़ने की ज़रूरत नहीं है.

एट्रिब्यूट:

android:mimeType
ContactsContract.Data टेबल में, कस्टम डेटा की लाइन के किसी टाइप के लिए आपने कस्टम एमआईएमई टाइप तय किया है. उदाहरण के लिए, वैल्यू vnd.android.cursor.item/vnd.example.locationstatus, डेटा की उस लाइन के लिए कस्टम एमआईएमई टाइप हो सकती है जो किसी संपर्क की आखिरी बार देखी गई जगह की जानकारी रिकॉर्ड करती है.
android:icon
Android का ड्रॉएबल रिसॉर्स, जिसे संपर्क ऐप्लिकेशन आपके डेटा के बगल में दिखाता है. इसका इस्तेमाल करके, उपयोगकर्ता को यह बताएं कि डेटा आपकी सेवा से मिला है.
android:summaryColumn
डेटा लाइन से मिली दो वैल्यू में से पहली वैल्यू के लिए कॉलम का नाम. यह वैल्यू, इस डेटा लाइन की एंट्री की पहली लाइन के तौर पर दिखती है. पहली लाइन का इस्तेमाल, डेटा की खास जानकारी के तौर पर किया जाता है. हालांकि, यह ज़रूरी नहीं है. यह भी देखें android:detailColumn.
android:detailColumn
यह डेटा लाइन से मिली दो वैल्यू में से दूसरी वैल्यू के कॉलम का नाम है. यह वैल्यू, इस डेटा लाइन की एंट्री की दूसरी लाइन के तौर पर दिखती है. android:summaryColumn भी देखें.

संपर्क सूची की सुविधा देने वाली अन्य कंपनियों की अतिरिक्त सुविधाएं

पिछले सेक्शन में बताई गई मुख्य सुविधाओं के अलावा, संपर्क सूची में संपर्क डेटा के साथ काम करने के लिए ये काम की सुविधाएं भी मिलती हैं:

  • संपर्क ग्रुप
  • फ़ोटो को बेहतर बनाने के लिए सुविधाएं

संपर्क ग्रुप

संपर्क सूची, एक जैसे संपर्कों के कलेक्शन को group डेटा के साथ लेबल कर सकती है. हालांकि, ऐसा करना ज़रूरी नहीं है. अगर किसी उपयोगकर्ता खाते से जुड़ा सर्वर ग्रुप बनाए रखना चाहता है, तो खाते के टाइप के लिए सिंक अडैप्टर को संपर्क सूची और सर्वर के बीच ग्रुप का डेटा ट्रांसफ़र करना चाहिए. जब उपयोगकर्ता सर्वर में कोई नया संपर्क जोड़ते हैं और फिर इस संपर्क को किसी नए ग्रुप में डालते हैं, तो सिंक अडैप्टर को ContactsContract.Groups टेबल में नया ग्रुप जोड़ना होगा. किसी रॉ संपर्क से जुड़े ग्रुप या ग्रुप की जानकारी, ContactsContract.Data टेबल में सेव की जाती है. इसके लिए, ContactsContract.CommonDataKinds.GroupMembership एमआईएमई टाइप का इस्तेमाल किया जाता है.

अगर आपको एक ऐसा सिंक अडैप्टर डिज़ाइन करना है जो सर्वर से संपर्क सूची में संपर्क का रॉ डेटा जोड़ेगा और आपको ग्रुप का इस्तेमाल नहीं करना है, तो आपको Provider को यह बताना होगा कि आपका डेटा दिखे. जब कोई उपयोगकर्ता डिवाइस में खाता जोड़ता है, तब एक्ज़ीक्यूट होने वाले कोड में, ContactsContract.Settings की उस लाइन को अपडेट करें जिसे संपर्क सूची ने खाते के लिए जोड़ा है. इस लाइन में, Settings.UNGROUPED_VISIBLE कॉलम की वैल्यू को 1 पर सेट करें. ऐसा करने पर, संपर्क सूची आपके संपर्कों का डेटा हमेशा दिखाएगा. भले ही, आपने ग्रुप का इस्तेमाल न किया हो.

संपर्क की फ़ोटो

ContactsContract.Data टेबल में, फ़ोटो को एमआईएमई टाइप Photo.CONTENT_ITEM_TYPE वाली लाइनों के तौर पर सेव किया जाता है. लाइन की CONTACT_ID कॉलम, उस रॉ संपर्क के _ID कॉलम से लिंक होता है जिससे वह जुड़ा होता है. क्लास ContactsContract.Contacts.Photo, ContactsContract.Contacts की एक सब-टेबल तय करती है. इसमें किसी संपर्क की मुख्य फ़ोटो की जानकारी होती है. यह संपर्क की मुख्य फ़ोटो होती है. इसी तरह, क्लास ContactsContract.RawContacts.DisplayPhoto, ContactsContract.RawContacts की एक सब-टेबल तय करती है. इसमें किसी रॉ संपर्क की मुख्य फ़ोटो की जानकारी होती है.

ContactsContract.Contacts.Photo और ContactsContract.RawContacts.DisplayPhoto के रेफ़रंस दस्तावेज़ में, फ़ोटो की जानकारी पाने के उदाहरण दिए गए हैं. किसी रॉ संपर्क के लिए मुख्य थंबनेल पाने के लिए, कोई सुविधा क्लास नहीं है. हालांकि, ContactsContract.Data टेबल को क्वेरी भेजी जा सकती है. इसके लिए, रॉ संपर्क के _ID, Photo.CONTENT_ITEM_TYPE, और IS_PRIMARY कॉलम को चुनें, ताकि रॉ संपर्क की मुख्य फ़ोटो वाली लाइन मिल सके.

किसी व्यक्ति के सोशल स्ट्रीम डेटा में फ़ोटो भी शामिल हो सकती हैं. इन्हें android.provider.ContactsContract.StreamItemPhotos टेबल में सेव किया जाता है. इसके बारे में ज़्यादा जानकारी, सोशल स्ट्रीम की फ़ोटो सेक्शन में दी गई है.