संपर्क सूची

Contacts Provider एक बेहतर और सुविधाजनक 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 में दिए गए हैं. कृपया टेबल के बाद दिए गए नोट पढ़ें:

टेबल 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 में लॉग इन किया, 'संपर्क' खोला, और "थॉमस हिगिन्सन" जोड़ा. बाद में, वह emilyd@gmail.com के तौर पर Gmail में लॉग इन करती है और "थॉमस हिगिन्सन" को एक ईमेल भेजती है. इससे, वह अपने-आप संपर्क के तौर पर जुड़ जाता है. वह Twitter पर "colonel_tom" (थॉमस हिगिन्सन का Twitter आईडी) को भी फ़ॉलो करती हैं.

इस काम की वजह से, संपर्कों की जानकारी देने वाली सेवा देने वाली कंपनी तीन रॉ संपर्क बनाती है:

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

डेटा

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

संपर्क

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

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

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

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

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

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

संपर्क सूची की मुख्य टेबल

तीसरी इमेज. Contacts, Raw Contacts, और Details टेबल के बीच के संबंध.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

जिन ऐप्लिकेशन को संपर्कों की जानकारी देने वाली सेवा को ऐक्सेस करना है उन्हें इन अनुमतियों का अनुरोध करना होगा:

एक या उससे ज़्यादा टेबल का रीड ऐक्सेस
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 क्लास में कॉन्स्टेंट उपलब्ध होते हैं.

उपयोगकर्ता की प्रोफ़ाइल को ऐक्सेस करने के लिए, खास अनुमतियों की ज़रूरत होती है. उपयोगकर्ता प्रोफ़ाइल को ऐक्सेस करने के लिए, रीड और लिखने की अनुमति के साथ-साथ, रीड और लिखने के लिए, क्रमशः android.Manifest.permission#READ_PROFILE और android.Manifest.permission#WRITE_PROFILE की अनुमतियां भी ज़रूरी हैं.READ_CONTACTSWRITE_CONTACTS

याद रखें कि आपको किसी उपयोगकर्ता की प्रोफ़ाइल को संवेदनशील मानना चाहिए. 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" पर सेट होता है.

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

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

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

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

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

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

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

  • यूनीक: किसी खाते के हर रॉ कॉन्टैक्ट का अपना सोर्स आईडी होना चाहिए. अगर ऐसा नहीं किया जाता है, तो आपको संपर्कों के ऐप्लिकेशन में समस्याएं आ सकती हैं. ध्यान दें कि एक ही खाता टाइप के दो रॉ संपर्कों का सोर्स आईडी एक ही हो सकता है. उदाहरण के लिए, खाते emily.dickinson@gmail.com के लिए रॉ संपर्क "Thomas Higginson" और खाते emilyd@gmail.com के लिए रॉ संपर्क "Thomas Higginson" का सोर्स आईडी एक ही हो सकता है.
  • स्थिर: सोर्स आईडी, रॉ संपर्क के लिए ऑनलाइन सेवा के डेटा का एक स्थायी हिस्सा होते हैं. उदाहरण के लिए, अगर उपयोगकर्ता ऐप्लिकेशन की सेटिंग से, संपर्कों का स्टोरेज मिटाता है और फिर से सिंक करता है, तो वापस लाए गए रॉ संपर्कों के सोर्स आईडी, पहले जैसे ही होने चाहिए. अगर ऐसा नहीं किया जाता है, तो शॉर्टकट काम करना बंद कर देंगे.
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 पंक्तियां वापस पाना चाहें. इसकी सुविधा देने के लिए, संपर्कों की जानकारी देने वाली कंपनी इकाई के कॉन्स्ट्रक्ट उपलब्ध कराती है. ये कॉन्स्ट्रक्ट, टेबल के बीच डेटाबेस जॉइन की तरह काम करते हैं.

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

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

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

नीचे दिए गए स्निपेट में, किसी संपर्क की सभी रॉ संपर्क पंक्तियां वापस पाने का तरीका बताया गया है. स्निपेट, बड़े ऐप्लिकेशन का हिस्सा है. इसमें दो गतिविधियां हैं, "मुख्य" और "जानकारी". मुख्य गतिविधि, संपर्क पंक्तियों की सूची दिखाती है. जब उपयोगकर्ता कोई पंक्ति चुनता है, तो गतिविधि, ज़्यादा जानकारी वाली गतिविधि को अपना आईडी भेजती है. ज़्यादा जानकारी वाली गतिविधि, चुने गए संपर्क से जुड़े सभी रॉ संपर्कों की सभी डेटा पंक्तियां दिखाने के लिए, 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 से डेटा पाकर उसे दिखाया जा सकता है या उस पर आगे काम किया जा सकता है.

एक साथ कई बदलाव करना

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

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

YielD पॉइंट

एक साथ कई बदलाव करने की सुविधा का इस्तेमाल करके, एक साथ कई बदलाव करने पर, अन्य प्रोसेस ब्लॉक हो सकती हैं. इससे, उपयोगकर्ता को खराब अनुभव मिल सकता है. आपको जिन बदलावों को करना है उन्हें व्यवस्थित करने के लिए, उन्हें कम से कम अलग-अलग सूचियों में रखें. साथ ही, उन्हें सिस्टम को ब्लॉक करने से रोकने के लिए, एक या उससे ज़्यादा ऑपरेशन के लिए यील्ड पॉइंट सेट करें. यील्ड पॉइंट एक ContentProviderOperation ऑब्जेक्ट होता है, जिसकी isYieldAllowed() वैल्यू को true पर सेट किया गया हो. जब संपर्कों की जानकारी देने वाली सेवा देने वाली कंपनी को कोई समस्या आती है, तो वह अपना काम रोक देती है, ताकि अन्य प्रोसेस चल सकें. साथ ही, वह मौजूदा लेन-देन को बंद कर देती है. जब सेवा देने वाली कंपनी फिर से शुरू होती है, तो वह 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 ऑब्जेक्ट के लिए, VERSION कॉलम की तुलना उस वर्शन नंबर से करने के लिए, withValue() को कॉल करें जिसे आपने अभी हासिल किया है.
  4. उसी ContentProviderOperation.Builder के लिए, withExpectedCount() को कॉल करें, ताकि यह पक्का किया जा सके कि इस दावे से सिर्फ़ एक लाइन की जांच की गई है.
  5. ContentProviderOperation ऑब्जेक्ट बनाने के लिए, build() को कॉल करें. इसके बाद, इस ऑब्जेक्ट को ArrayList में पहले ऑब्जेक्ट के तौर पर जोड़ें, जिसे applyBatch() को पास किया जाता है.
  6. एक साथ कई लेन-देन करने की सुविधा लागू करें.

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

नीचे दिए गए स्निपेट में, CursorLoader का इस्तेमाल करके किसी एक रॉ संपर्क के लिए क्वेरी करने के बाद, "असर्ट" 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 में, उपलब्ध टास्क के लिए इस्तेमाल की जाने वाली कार्रवाई, MIME टाइप, और डेटा वैल्यू की खास जानकारी दी गई है. वहीं, putExtra() के साथ इस्तेमाल की जा सकने वाली अतिरिक्त वैल्यू, ContactsContract.Intents.Insert के रेफ़रंस दस्तावेज़ में दी गई हैं:

टेबल 4. संपर्क सूची की सेवा देने वाली कंपनी के इंटेंट.

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

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

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

ध्यान दें: इस इंटेंट के एक्सट्रा में नाम की वैल्यू भेजने की ज़रूरत नहीं है, क्योंकि उपयोगकर्ता हमेशा कोई मौजूदा नाम चुनता है या नया नाम जोड़ता है. इसके अलावा, अगर आपने कोई नाम भेजा है और उपयोगकर्ता ने उसमें बदलाव करने का विकल्प चुना है, तो 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);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

एक Service कॉम्पोनेंट, जो सिंक एडैप्टर से बाइंड करने के लिए, सिस्टम के अनुरोधों का जवाब देता है.
जब सिस्टम को सिंक करना होता है, तो वह सिंक एडेप्टर के लिए IBinder पाने के लिए, सेवा के onBind() तरीके को कॉल करता है. इससे सिस्टम, अडैप्टर के तरीकों पर क्रॉस-प्रोसेस कॉल कर सकता है.
असल सिंक अडैप्टर, जिसे AbstractThreadedSyncAdapter के कंक्रीट सबक्लास के तौर पर लागू किया गया है.
यह क्लास, सर्वर से डेटा डाउनलोड करने, डिवाइस से डेटा अपलोड करने, और विरोधों को हल करने का काम करती है. अडैप्टर का मुख्य काम, onPerformSync() तरीके से किया जाता है. इस क्लास को सिंगलटन के तौर पर इंस्टैंशिएट किया जाना चाहिए.
Application की सब-क्लास.
यह क्लास, सिंक अडैप्टर सिंगलटन के लिए फ़ैक्ट्री के तौर पर काम करती है. सिंक अडैप्टर को इंस्टैंशिएट करने के लिए, onCreate() तरीके का इस्तेमाल करें. साथ ही, सिंक अडैप्टर की सेवा के onBind() तरीके में सिंगलटन को वापस लाने के लिए, स्टैटिक "गेटर" तरीका दें.
ज़रूरी नहीं: यह एक Service कॉम्पोनेंट है, जो उपयोगकर्ता की पुष्टि करने के लिए, सिस्टम से मिले अनुरोधों का जवाब देता है.
AccountManager, पुष्टि की प्रोसेस शुरू करने के लिए, इस सेवा को शुरू करता है. सेवा का onCreate() तरीका, authenticator ऑब्जेक्ट को इंस्टैंशिएट करता है. जब सिस्टम को ऐप्लिकेशन के सिंक अडैप्टर के लिए किसी उपयोगकर्ता खाते की पुष्टि करनी होती है, तो वह पुष्टि करने वाले टूल के लिए IBinder पाने के लिए, सेवा के onBind() तरीके को कॉल करता है. इससे सिस्टम को पुष्टि करने वाले तरीकों के लिए, क्रॉस-प्रोसेस कॉल करने में मदद मिलती है.
ज़रूरी नहीं: 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
यह एक टेक्स्ट स्ट्रिंग है, जिसमें स्ट्रीम आइटम को डालने या अपडेट करने का समय होता है. यह समय, मिलीसेकंड में, एपिक के बाद के समय के तौर पर दिया जाता है. स्ट्रीम आइटम डालने या अपडेट करने वाले ऐप्लिकेशन, इस कॉलम को मैनेज करने के लिए ज़िम्मेदार होते हैं. यह कॉलम, संपर्कों की जानकारी देने वाली सेवा देने वाली कंपनी के ज़रिए अपने-आप मैनेज नहीं होता.

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

सोशल स्ट्रीम से जुड़े इंटरैक्शन

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

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

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

सोशल नेटवर्किंग साइटों पर वीडियो के व्यू मैनेज करने के लिए रजिस्टर करना

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

  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> एलिमेंट में दी गई है.

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

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

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

  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
आपके ऐप्लिकेशन में मौजूद किसी ऐसी गतिविधि की पूरी तरह क्वालिफ़ाइड क्लास का नाम जो ग्रुप की जानकारी दिखा सकती है. जब उपयोगकर्ता डिवाइस के संपर्क ऐप्लिकेशन में ग्रुप लेबल पर क्लिक करता है, तो इस गतिविधि के लिए यूज़र इंटरफ़ेस (यूआई) दिखता है.
viewGroupActionLabel
वह लेबल जो संपर्कों के ऐप्लिकेशन में, यूज़र इंटरफ़ेस (यूआई) कंट्रोल के लिए दिखता है. इससे उपयोगकर्ता को आपके ऐप्लिकेशन में ग्रुप देखने की अनुमति मिलती है.

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

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

<ContactsDataKind> एलिमेंट

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

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

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

<ContactsAccountType>

जानकारी:

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

एट्रिब्यूट:

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

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

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

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

संपर्क ग्रुप

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

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

संपर्क सूची में शामिल लोगों की फ़ोटो

ContactsContract.Data टेबल, फ़ोटो को MIME टाइप 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 टेबल में सेव किया जाता है. इस टेबल के बारे में ज़्यादा जानकारी, सोशल स्ट्रीम की फ़ोटो सेक्शन में दी गई है.