পরিচিতি সরবরাহকারী

পরিচিতি সরবরাহকারী হল একটি শক্তিশালী এবং নমনীয় Android কম্পোনেন্ট যা ডিভাইসের লোকজনের ডেটার সেন্ট্রাল রিপোজিটরি ম্যানেজ করে। পরিচিতি সরবরাহকারী হল ডেটার সোর্স যা আপনি ডিভাইসের পরিচিতি অ্যাপ্লিকেশনে দেখতে পান এবং আপনি নিজের অ্যাপ্লিকেশনেও এর ডেটা অ্যাক্সেস করতে পারেন এবং ডিভাইস ও অনলাইন পরিষেবার মধ্যে ডেটা ট্রান্সফার করতে পারেন। প্রদানকারী বিভিন্ন ধরনের ডেটা সোর্স ব্যবহার করে এবং প্রতিটি ব্যক্তির জন্য যতটা সম্ভব ডেটা ম্যানেজ করার চেষ্টা করে, যার ফলে এর সংগঠন জটিল হয়। এই কারণে, প্রদানকারীর API-তে কনট্র্যাক্ট ক্লাস ও ইন্টারফেসের একটি বিস্তৃত সেট অন্তর্ভুক্ত থাকে যা ডেটা রিট্রিভ ও পরিবর্তন, দুটিই সহজ করে তোলে।

এই নির্দেশিকায় নিম্নলিখিত বিষয়গুলি বর্ণনা করা হয়েছে:

  • প্রোভাইডারের বেসিক স্ট্রাকচার।
  • পরিষেবা প্রদানকারীর থেকে কীভাবে ডেটা ফিরিয়ে আনবেন।
  • প্রোভাইডারে কীভাবে ডেটা পরিবর্তন করবেন।
  • আপনার সার্ভার থেকে পরিচিতি সরবরাহকারীতে ডেটা সিঙ্ক করার জন্য কীভাবে সিঙ্ক অ্যাডাপ্টার লিখতে হয়।

এই নির্দেশিকা ধরে নেয় যে আপনি Android কন্টেন্ট প্রোভাইডার সম্পর্কে প্রাথমিক বিষয়গুলি জানেন। Android কন্টেন্ট প্রোভাইডার সম্পর্কে আরও জানতে, কন্টেন্ট প্রোভাইডার সংক্রান্ত প্রাথমিক তথ্য গাইড পড়ুন।

পরিচিতি সরবরাহকারী সংস্থা

পরিচিতি সরবরাহকারী হল Android কন্টেন্ট প্রোভাইডার কম্পোনেন্ট। এটি কোনও ব্যক্তির সম্পর্কে তিন ধরনের ডেটা মেইনটেইন করে, যার প্রতিটি প্রদানকারীর অফার করা টেবিলের সাথে সম্পর্কিত, যেমন ছবি ১-এ দেখানো হয়েছে:

ছবি ১. পরিচিতি সরবরাহকারী টেবিল স্ট্রাকচার।

তিনটি টেবিলকে সাধারণত তাদের কনট্র্যাক্ট ক্লাসের নাম দ্বারা উল্লেখ করা হয়। ক্লাসগুলি টেবিল দ্বারা ব্যবহৃত কন্টেন্ট URI, কলামের নাম এবং কলামের মানের জন্য ধ্রুবক সংজ্ঞায়িত করে:

ContactsContract.Contactsটি সারণী
র কন্ট্যাক্ট সারির অ্যাগ্রিগেশনের উপর ভিত্তি করে বিভিন্ন ব্যক্তিকে উপস্থাপন করা সারি।
ContactsContract.RawContactsটি সারণী
ব্যবহারকারীর অ্যাকাউন্ট ও ধরন অনুযায়ী, কোনও ব্যক্তির ডেটার সারসংক্ষেপ সহ সারি।
ContactsContract.Dataটি সারণী
র কন্ট্যাক্টের বিবরণ সহ সারি, যেমন ইমেল আইডি বা ফোন নম্বর।

ContactsContract-এ কনট্র্যাক্ট ক্লাস দ্বারা উপস্থাপিত অন্যান্য টেবিলগুলি হল সহায়ক টেবিল যা পরিচিতি সরবরাহকারী তার ক্রিয়াকলাপ পরিচালনা করতে বা ডিভাইসের পরিচিতি বা টেলিফোনি অ্যাপ্লিকেশনগুলিতে নির্দিষ্ট ফাংশন সমর্থন করতে ব্যবহার করে।

র কন্ট্যাক্ট

র কন্ট্যাক্ট হল কোনও ব্যক্তির ডেটা যা একটি অ্যাকাউন্টের ধরন ও অ্যাকাউন্টের নাম থেকে আসে। যেহেতু পরিচিতি সরবরাহকারী কোনও ব্যক্তির ডেটার সোর্স হিসেবে একাধিক অনলাইন পরিষেবার অনুমতি দেয়, তাই পরিচিতি সরবরাহকারী একই ব্যক্তির জন্য একাধিক র কন্ট্যাক্টের অনুমতি দেয়। এছাড়াও, একাধিক র কন্ট্যাক্ট একজন ব্যবহারকারীকে একই ধরনের অ্যাকাউন্ট থেকে একাধিক অ্যাকাউন্টের মাধ্যমে কোনও ব্যক্তির ডেটা একত্রিত করার অনুমতি দেয়।

র কন্ট্যাক্টের বেশিরভাগ ডেটা ContactsContract.RawContacts টেবিলে সেভ করা হয় না। পরিবর্তে, এটি ContactsContract.Data টেবিলের এক বা একাধিক সারিতে স্টোর করা হয়। প্রতিটি ডেটা সারিতে একটি কলাম Data.RAW_CONTACT_ID থাকে যেটিতে মূল ContactsContract.RawContacts সারির RawContacts._ID ভ্যালু থাকে।

গুরুত্বপূর্ণ র কন্ট্যাক্ট কলাম

ContactsContract.RawContacts টেবিলের গুরুত্বপূর্ণ কলামগুলি টেবিল ১-এ তালিকাভুক্ত করা আছে। টেবিলের পরে দেওয়া নোটগুলি পড়ুন:

টেবিল ১. গুরুত্বপূর্ণ র কন্ট্যাক্ট কলাম।

কলামের নাম ব্যবহার করুন নোট
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" ব্যবহারকারীর কথা ভাবুন যার ডিভাইসে নিম্নলিখিত তিনটি ব্যবহারকারীর অ্যাকাউন্ট আছে:

  • emily.dickinson@gmail.com
  • emilyd@gmail.com
  • "belle_of_amherst" Twitter অ্যাকাউন্ট

এই ব্যবহারকারী অ্যাকাউন্ট সেটিংস থেকে এই তিনটি অ্যাকাউন্টের জন্যই পরিচিতি সিঙ্ক করুন বিকল্প চালু করেছেন।

ধরা যাক, Emily Dickinson একটি ব্রাউজার উইন্ডো খুলে, emily.dickinson@gmail.com হিসেবে Gmail-এ লগ-ইন করে, Contacts খুলে, "Thomas Higginson"-কে যোগ করে। পরে, তিনি emilyd@gmail.com হিসেবে Gmail-এ লগ-ইন করেন এবং "Thomas Higginson"-কে ইমেল পাঠান, যা অটোমেটিক তাকে পরিচিতি হিসেবে যোগ করে। এছাড়াও, তিনি Twitter-এ "colonel_tom" (Thomas Higginson-এর Twitter ID) ফলো করেন।

এই কাজের ফলে পরিচিতি সরবরাহকারী তিনটি র কন্ট্যাক্ট তৈরি করে:

  1. emily.dickinson@gmail.com-এর সাথে যুক্ত "Thomas Higginson"-এর জন্য একটি র কন্ট্যাক্ট। ব্যবহারকারীর অ্যাকাউন্টের ধরন হল Google।
  2. emilyd@gmail.com-এর সাথে যুক্ত "Thomas Higginson"-এর জন্য দ্বিতীয় র কন্ট্যাক্ট। ব্যবহারকারীর অ্যাকাউন্টের ধরনও Google। আগের নামের সাথে একই নাম হওয়া সত্ত্বেও দ্বিতীয় একটি র কন্ট্যাক্ট আছে, কারণ এই ব্যক্তিকে অন্য একটি ব্যবহারকারীর অ্যাকাউন্টের জন্য যোগ করা হয়েছে।
  3. "belle_of_amherst"-এর সাথে যুক্ত "Thomas Higginson"-এর জন্য তৃতীয় র কন্ট্যাক্ট। ব্যবহারকারীর অ্যাকাউন্টের ধরন হল Twitter।

ডেটা

আগে যেমন উল্লেখ করা হয়েছে, র কন্ট্যাক্টের ডেটা ContactsContract.Data সারিতে স্টোর করা হয় যা র কন্ট্যাক্টের _ID ভ্যালুর সাথে লিঙ্ক করা থাকে। এটি একটি র কন্ট্যাক্টকে একই ধরনের ডেটার একাধিক ইনস্ট্যান্স রাখার অনুমতি দেয়, যেমন ইমেল আইডি বা ফোন নম্বর। যেমন, emilyd@gmail.com-এর জন্য "Thomas Higginson" (Google অ্যাকাউন্ট emilyd@gmail.com-এর সাথে যুক্ত Thomas Higginson-এর র কন্ট্যাক্ট সারি)-এর বাড়ির ইমেল আইডি thigg@gmail.com এবং অফিসের ইমেল আইডি thomas.higginson@gmail.com হলে, Contacts Provider দুটি ইমেল আইডির সারি স্টোর করে এবং দুটিকেই র কন্ট্যাক্টের সাথে লিঙ্ক করে।

লক্ষ্য করুন যে এই একটি টেবিলে বিভিন্ন ধরনের ডেটা স্টোর করা আছে। যে নাম দেখানো হবে, ফোন নম্বর, ইমেল, পোস্টাল অ্যাড্রেস, ফটো এবং ওয়েবসাইট সংক্রান্ত বিবরণের সারিগুলি সবই ContactsContract.Data টেবিলে পাওয়া যাবে। এটি ম্যানেজ করতে সাহায্য করার জন্য, ContactsContract.Data টেবিলে কিছু কলামে বর্ণনামূলক নাম আছে, এবং অন্যদের সাধারণ নাম আছে। বর্ণনামূলক-নাম কলামের কন্টেন্টের অর্থ একই থাকে, সেটি সারির ডেটার ধরনের উপর নির্ভর করে না, তবে সাধারণ-নাম কলামের কন্টেন্টের অর্থ ডেটার ধরনের উপর নির্ভর করে আলাদা হয়।

কলামের বর্ণনামূলক নাম

বর্ণনামূলক কলামের নামের কিছু উদাহরণ হল:

RAW_CONTACT_ID
এই ডেটার জন্য র কন্ট্যাক্টের _ID কলামের ভ্যালু।
MIMETYPE
এই সারিতে স্টোর করা ডেটার ধরন, কাস্টম MIME টাইপ হিসেবে প্রকাশ করা হয়েছে। পরিচিতি সরবরাহকারী ContactsContract.CommonDataKinds-এর সাবক্লাসে সংজ্ঞায়িত MIME-এর প্রকার ব্যবহার করে। এই MIME-এর প্রকারগুলি ওপেন সোর্স, এবং পরিচিতি সরবরাহকারীর সাথে কাজ করে এমন যেকোনও অ্যাপ্লিকেশন বা সিঙ্ক অ্যাডাপ্টার দ্বারা ব্যবহার করা যেতে পারে।
IS_PRIMARY
কোনও র কন্ট্যাক্টের জন্য এই ধরনের ডেটা সারি একাধিকবার থাকলে, IS_PRIMARY কলাম সেই ডেটা সারিকে ফ্ল্যাগ করে যাতে এই ধরনের প্রাথমিক ডেটা থাকে। যেমন, ব্যবহারকারী কোনও পরিচিতির ফোন নম্বরে বেশিক্ষণ প্রেস করে ডিফল্ট হিসেবে সেট করুন বিকল্প বেছে নিলে, সেই নম্বর সহ ContactsContract.Data সারির IS_PRIMARY কলামের মান শূন্য ছাড়া অন্য কিছুতে সেট করা হয়।

জেনেরিক কলামের নাম

DATA1 থেকে DATA15 পর্যন্ত ১৫টি জেনেরিক কলাম আছে যা সাধারণত উপলভ্য থাকে এবং SYNC1 থেকে SYNC4 পর্যন্ত আরও চারটি জেনেরিক কলাম আছে যা শুধুমাত্র সিঙ্ক অ্যাডাপ্টারের ব্যবহার করা উচিত। রোতে যে ধরনের ডেটাই থাকুক না কেন, জেনেরিক কলামের নামের কনস্ট্যান্ট সবসময় কাজ করে।

DATA1 কলামটি ইন্ডেক্স করা হয়েছে। পরিচিতি সরবরাহকারী সবসময় এই কলামটি সেই ডেটার জন্য ব্যবহার করে যেটি সরবরাহকারী আশা করে যে কোনও কোয়েরির সবচেয়ে ঘন ঘন টার্গেট হবে। যেমন, ইমেলের সারিতে, এই কলামে আসল ইমেল আইডি থাকে।

কনভেনশন অনুযায়ী, DATA15 কলামটি ফটো থাম্বনেলের মতো বাইনারি লার্জ অবজেক্ট (BLOB) ডেটা স্টোর করার জন্য রিজার্ভ করা থাকে।

ধরন-নির্দিষ্ট কলামের নাম

নির্দিষ্ট ধরনের সারির কলামের সাথে কাজ করার সুবিধা দিতে, পরিচিতি সরবরাহকারী নির্দিষ্ট ধরনের কলামের নাম কনস্ট্যান্টও প্রদান করে, যা ContactsContract.CommonDataKinds-এর সাবক্লাসে সংজ্ঞায়িত করা থাকে। কনস্ট্যান্টগুলি কেবল একই কলামের নামের জন্য একটি ভিন্ন কনস্ট্যান্ট নাম দেয়, যা আপনাকে একটি নির্দিষ্ট ধরনের সারিতে ডেটা অ্যাক্সেস করতে সহায়তা করে।

যেমন, ContactsContract.CommonDataKinds.Email ক্লাস, ContactsContract.Data সারির জন্য টাইপ-নির্দিষ্ট কলামের নাম কনস্ট্যান্টকে সংজ্ঞায়িত করে যার MIME টাইপ হল Email.CONTENT_ITEM_TYPE। ক্লাসে ইমেল আইডি কলামের জন্য ADDRESS কনস্ট্যান্ট আছে। ADDRESS-এর আসল ভ্যালু হল "data1", যা কলামের সাধারণ নামের মতোই।

সতর্কতা: ContactsContract.Data টেবিলে আপনার নিজস্ব কাস্টম ডেটা যোগ করবেন না। প্রোভাইডারের আগে থেকে নির্ধারিত MIME টাইপ আছে এমন সারি ব্যবহার করে এটি করবেন না। আপনি যদি তা করেন, তাহলে আপনি ডেটা হারাতে পারেন বা প্রদানকারীর সমস্যা হতে পারে। যেমন, MIME-এর প্রকার Email.CONTENT_ITEM_TYPE সহ কোনও সারি যোগ করা উচিত নয়, যেখানে DATA1 কলামে ইমেল আইডির পরিবর্তে ব্যবহারকারীর নাম থাকে। আপনি যদি সারির জন্য নিজের কাস্টম MIME-এর প্রকার ব্যবহার করেন, তাহলে আপনি নিজের প্রকার-নির্দিষ্ট কলামের নাম সংজ্ঞায়িত করতে এবং আপনার ইচ্ছামতো কলাম ব্যবহার করতে পারবেন।

ছবি ২-এ দেখানো হয়েছে যে কীভাবে বর্ণনামূলক কলাম এবং ডেটা কলাম একটি ContactsContract.Data সারিতে দেখা যায় এবং কীভাবে ধরন-নির্দিষ্ট কলামের নাম জেনেরিক কলামের নামের উপর "ওভারলে" করে

কীভাবে ধরন-নির্দিষ্ট কলামের নাম সাধারণ কলামের নামের সাথে ম্যাপ করা হয়

ছবি ২. ধরন-নির্দিষ্ট কলামের নাম এবং সাধারণ কলামের নাম।

ধরন-নির্দিষ্ট কলামের নামের ক্লাস

সারণী ২-এ সবচেয়ে বেশি ব্যবহৃত ধরন-নির্দিষ্ট কলামের নামের ক্লাস তালিকাভুক্ত করা হয়েছে:

সারণী ২. ধরন-নির্দিষ্ট কলামের নামের ক্লাস

ম্যাপিং ক্লাস ডেটার ধরন নোট
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 কলামও আছে যা পরিচিতি সারির "স্থায়ী" লিঙ্ক। পরিচিতি সরবরাহকারী অটোমেটিক পরিচিতি ম্যানেজ করে বলে, এটি কোনও অ্যাগ্রিগেশন বা সিঙ্কের উত্তরে পরিচিতির সারির _ID ভ্যালু পরিবর্তন করতে পারে। এমনকি এটি ঘটলেও, কন্টেন্ট URI CONTENT_LOOKUP_URI-এর সাথে পরিচিতির LOOKUP_KEY এখনও পরিচিতির সারি দেখাবে, তাই আপনি LOOKUP_KEY ব্যবহার করে "পছন্দের" পরিচিতির লিঙ্ক বজায় রাখতে পারবেন এবং আরও অনেক কিছু করতে পারবেন। এই কলামের নিজস্ব ফর্ম্যাট আছে যা _ID কলামের ফর্ম্যাটের সাথে সম্পর্কিত নয়।

তিনটি প্রধান টেবিল কীভাবে একে অপরের সাথে সম্পর্কিত তা চিত্র ৩-এ দেখানো হয়েছে।

পরিচিতি সরবরাহকারীর মূল টেবিল

ছবি ৩. পরিচিতি, র কন্ট্যাক্ট ও বিবরণ টেবিলের মধ্যে সম্পর্ক।

সতর্কতা: আপনি যদি Google Play Store-এ আপনার অ্যাপ প্রকাশ করেন অথবা আপনার অ্যাপটি Android ১০ (API লেভেল ২৯) বা তার পরবর্তী ভার্সনে চলা কোনও ডিভাইসে থাকে, তাহলে মনে রাখবেন যে পরিচিতি ডেটা ফিল্ড এবং পদ্ধতির একটি সীমিত সেট বাতিল করা হয়েছে।

উল্লেখ করা শর্ত অনুযায়ী, সিস্টেম নির্দিষ্ট সময় অন্তর এইসব ডেটা ফিল্ডে লেখা যেকোনও ভ্যালু মুছে দেয়:

উপরের ডেটা ফিল্ড সেট করতে ব্যবহৃত API-ও বাতিল করা হয়েছে:

এছাড়াও, নিম্নলিখিত ফিল্ডগুলি আর ঘন ঘন যোগাযোগ করা পরিচিতি দেখায় না। মনে রাখবেন যে এই ফিল্ডগুলির মধ্যে কিছু পরিচিতির র‍্যাঙ্কিংকে প্রভাবিত করে শুধুমাত্র যখন পরিচিতিগুলি একটি নির্দিষ্ট ডেটা ধরনের অংশ হয়।

আপনার অ্যাপ এইসব ফিল্ড বা API অ্যাক্সেস বা আপডেট করলে, বিকল্প পদ্ধতি ব্যবহার করুন। যেমন, আপনি ব্যক্তিগত কন্টেন্ট প্রোভাইডার বা আপনার অ্যাপ বা ব্যাকএন্ড সিস্টেমে স্টোর করা অন্যান্য ডেটা ব্যবহার করে নির্দিষ্ট কিছু ব্যবহারের ক্ষেত্রে পূরণ করতে পারেন।

এই পরিবর্তনের ফলে আপনার অ্যাপের কার্যকারিতা প্রভাবিত হয়নি তা যাচাই করতে, আপনি ম্যানুয়ালি এইসব ডেটা ফিল্ড মুছে দিতে পারেন। এটি করতে, Android 4.1 (API লেভেল ১৬) বা তার পরবর্তী যেকোনও ভার্সনে চলা ডিভাইসে নিম্নলিখিত 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 অ্যাকাউন্ট কনফিগার করতে এবং Contacts Provider-এ তাদের ডেটা ডাউনলোড করতে পারেন; ব্যবহারকারীর ব্যক্তিগত অ্যাকাউন্টের নামের জন্য ব্যক্তিগত পরিচিতির একটি সেট এবং কাজের জন্য আরেকটি সেট থাকলে এটি হতে পারে। অ্যাকাউন্টের নাম সাধারণত অনন্য হয়। একসাথে, তারা পরিচিতি সরবরাহকারী এবং একটি বাহ্যিক পরিষেবার মধ্যে একটি নির্দিষ্ট ডেটা ফ্লো শনাক্ত করে।

আপনি যদি আপনার পরিষেবার ডেটা পরিচিতি সরবরাহকারীতে ট্রান্সফার করতে চান, তাহলে আপনাকে নিজের সিঙ্ক অ্যাডাপ্টার লিখতে হবে। পরিচিতি সরবরাহকারী সিঙ্ক অ্যাডাপ্টার বিভাগে এই বিষয়ে আরও বিস্তারিতভাবে বর্ণনা করা হয়েছে।

ছবি ৪-এ দেখানো হয়েছে যে কীভাবে পরিচিতি সরবরাহকারী লোকজনের ডেটার ফ্লোতে ফিট করে। "সিঙ্ক অ্যাডাপ্টার" হিসেবে চিহ্নিত বক্সে, প্রতিটি অ্যাডাপ্টারকে তার অ্যাকাউন্টের ধরন অনুযায়ী লেবেল করা হয়।

লোকজন সম্পর্কে ডেটার ফ্লো

ছবি ৪. পরিচিতি সরবরাহকারীর ডেটার ফ্লো।

প্রয়োজনীয় অনুমতি

যেসব অ্যাপ্লিকেশন পরিচিতি সরবরাহকারী অ্যাক্সেস করতে চায়, সেগুলিকে নিম্নলিখিত অনুমতিগুলির জন্য অনুরোধ করতে হবে:

এক বা একাধিক টেবিল পড়ার অ্যাক্সেস
READ_CONTACTS, AndroidManifest.xml-এ <uses-permission> এলিমেন্ট সহ <uses-permission android:name="android.permission.READ_CONTACTS"> হিসেবে উল্লেখ করা হয়েছে।
এক বা একাধিক টেবিলে লেখার অ্যাক্সেস
WRITE_CONTACTS, AndroidManifest.xml-এ <uses-permission> এলিমেন্ট সহ <uses-permission android:name="android.permission.WRITE_CONTACTS"> হিসেবে উল্লেখ করা হয়েছে।

এইসব অনুমতি ব্যবহারকারীর প্রোফাইল ডেটার ক্ষেত্রে প্রযোজ্য নয়। ব্যবহারকারীর প্রোফাইল এবং এর প্রয়োজনীয় অনুমতি সম্পর্কে নিম্নলিখিত বিভাগে আলোচনা করা হয়েছে, ব্যবহারকারীর প্রোফাইল।

মনে রাখবেন যে ব্যবহারকারীর পরিচিতির ডেটা ব্যক্তিগত এবং সংবেদনশীল। ব্যবহারকারীরা তাদের গোপনীয়তা নিয়ে চিন্তিত, তাই তারা চান না যে অ্যাপ্লিকেশন তাদের বা তাদের পরিচিতি সম্পর্কে ডেটা সংগ্রহ করুক। ব্যবহারকারীর পরিচিতি ডেটা অ্যাক্সেস করার অনুমতি আপনার কেন প্রয়োজন তা স্পষ্ট না হলে, তিনি আপনার অ্যাপ্লিকেশনকে কম রেটিং দিতে পারেন বা সেটি ইনস্টল করতে অস্বীকার করতে পারেন।

ব্যবহারকারীর প্রোফাইল

ContactsContract.Contacts টেবিলে একটি মাত্র সারি আছে, যাতে ডিভাইসের ব্যবহারকারীর প্রোফাইল ডেটা আছে। এই ডেটা ব্যবহারকারীর কোনও পরিচিতির পরিবর্তে ডিভাইসের user বর্ণনা করে। প্রোফাইল ব্যবহার করে এমন প্রতিটি সিস্টেমের জন্য প্রোফাইল পরিচিতি সারিটি একটি র পরিচিতি সারির সাথে লিঙ্ক করা থাকে। প্রতিটি প্রোফাইল র কন্ট্যাক্ট সারিতে একাধিক ডেটা সারি থাকতে পারে। ব্যবহারকারীর প্রোফাইল অ্যাক্সেস করার জন্য কনস্ট্যান্ট ContactsContract.Profile ক্লাসে উপলভ্য।

ব্যবহারকারীর প্রোফাইল অ্যাক্সেস করার জন্য বিশেষ অনুমতি প্রয়োজন। রিড ও রাইট করার জন্য প্রয়োজনীয় READ_CONTACTS এবং WRITE_CONTACTS অনুমতি ছাড়াও, ব্যবহারকারীর প্রোফাইল অ্যাক্সেস করার জন্য রিড ও রাইট অ্যাক্সেসের জন্য যথাক্রমে android.Manifest.permission#READ_PROFILE এবং android.Manifest.permission#WRITE_PROFILE অনুমতি প্রয়োজন।

মনে রাখবেন, ব্যবহারকারীর প্রোফাইলকে সংবেদনশীল হিসেবে বিবেচনা করা উচিত। android.Manifest.permission#READ_PROFILE অনুমতি আপনাকে ডিভাইসের ব্যবহারকারীর ব্যক্তিগতভাবে শনাক্তকরণযোগ্য ডেটা অ্যাক্সেস করার অনুমতি দেয়। আপনার অ্যাপ্লিকেশনের বিবরণে ব্যবহারকারীকে অবশ্যই জানান যে কেন আপনার ব্যবহারকারীর প্রোফাইল অ্যাক্সেস করার অনুমতি প্রয়োজন।

ব্যবহারকারীর প্রোফাইল আছে এমন পরিচিতির সারি ফিরিয়ে আনতে, ContentResolver.query()-এ কল করুন। কন্টেন্ট URI CONTENT_URI-এ সেট করুন এবং কোনও বাছাইয়ের মাপকাঠি দেবেন না। এছাড়াও, আপনি এই কন্টেন্ট URI-কে প্রোফাইলের জন্য র কন্ট্যাক্ট বা ডেটা ফিরিয়ে আনার জন্য বেস 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
)

জাভা

// 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 কলামটি পরীক্ষা করুন। পরিচিতিটি ব্যবহারকারীর প্রোফাইল হলে, এই কলামটি "১" হিসেবে সেট করা হয়।

পরিচিতি সরবরাহকারী মেটাডেটা

পরিচিতি সরবরাহকারী এমন ডেটা ম্যানেজ করে যা রিপোজিটরিতে পরিচিতি ডেটার স্ট্যাটাস ট্র্যাক করে। রিপোজিটরি সংক্রান্ত এই মেটাডেটা বিভিন্ন জায়গায় স্টোর করা হয়, যার মধ্যে রয়েছে র কন্ট্যাক্ট, ডেটা এবং পরিচিতি টেবিলের সারি, ContactsContract.Settings টেবিল এবং ContactsContract.SyncState টেবিল। নিম্নলিখিত সারণীতে এই প্রতিটি মেটাডেটার প্রভাব দেখানো হয়েছে:

সারণী ৩. পরিচিতি সরবরাহকারীতে মেটাডেটা

টেবিল কলাম মান অর্থ
ContactsContract.RawContacts DIRTY "0" - শেষবার সিঙ্ক করার পর থেকে পরিবর্তন করা হয়নি। ডিভাইসে পরিবর্তন করা হয়েছে এবং সার্ভারে আবার সিঙ্ক করতে হবে এমন র কন্ট্যাক্ট চিহ্নিত করে। Android অ্যাপ্লিকেশন কোনও সারি আপডেট করলে, পরিচিতি সরবরাহকারী অটোমেটিক ভ্যালু সেট করে।

র কন্ট্যাক্ট বা ডেটা টেবিল পরিবর্তন করে এমন সিঙ্ক অ্যাডাপ্টারকে সবসময় তাদের ব্যবহার করা কন্টেন্ট URI-তে CALLER_IS_SYNCADAPTER স্ট্রিং যোগ করতে হবে। এটি প্রদানকারীকে সারিগুলিকে নোংরা হিসাবে চিহ্নিত করা থেকে বাধা দেয়। অন্যথায়, সিঙ্ক অ্যাডাপ্টারের পরিবর্তনগুলি লোকাল পরিবর্তন হিসেবে দেখা যায় এবং সার্ভারে পাঠানো হয়, যদিও সার্ভারটি পরিবর্তনের সোর্স ছিল।

"১" - শেষবার সিঙ্ক করার পর থেকে পরিবর্তন করা হয়েছে, সার্ভারে আবার সিঙ্ক করতে হবে।
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 অ্যাপ্লিকেশন UI-তে দেখা যাবে না। এই কলামটি এমন সার্ভারের সাথে মানানসই যা ব্যবহারকারীকে নির্দিষ্ট গ্রুপে পরিচিতি আড়াল করার অনুমতি দেয়।
"১" - এই গ্রুপের পরিচিতিগুলি অ্যাপ্লিকেশন UI-তে দেখার অনুমতি দেওয়া হয়েছে।
ContactsContract.Settings UNGROUPED_VISIBLE "0" - এই অ্যাকাউন্ট এবং অ্যাকাউন্টের ধরনের জন্য, কোনও গ্রুপের অন্তর্গত নয় এমন পরিচিতিগুলি Android অ্যাপ্লিকেশন UI-তে দেখা যায় না। ডিফল্ট হিসেবে, কোনও র কন্ট্যাক্ট কোনও গ্রুপের অন্তর্ভুক্ত না হলে, কন্ট্যাক্ট দেখা যায় না (র কন্ট্যাক্টের জন্য গ্রুপ মেম্বারশিপ এক বা একাধিক ContactsContract.CommonDataKinds.GroupMembership সারি দ্বারা ContactsContract.Data টেবিলে দেখানো হয়)। অ্যাকাউন্টের ধরন ও অ্যাকাউন্টের জন্য ContactsContract.Settings টেবিল সারিতে এই ফ্ল্যাগ সেট করে, আপনি গ্রুপ ছাড়া পরিচিতিগুলিকে দেখতে বাধ্য করতে পারেন। এই ফ্ল্যাগ ব্যবহার করার একটি উদ্দেশ্য হল, গ্রুপ ব্যবহার করে না এমন সার্ভার থেকে পরিচিতি দেখানো।
"১" - এই অ্যাকাউন্ট এবং অ্যাকাউন্টের ধরনের জন্য, কোনও গ্রুপের অন্তর্গত নয় এমন পরিচিতি অ্যাপ্লিকেশন UI-তে দেখা যায়।
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.
    )
}

জাভা

...
    /*
     * 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() কল করে, "ব্যাচ মোডে" পরিচিতি সরবরাহকারীতে ডেটা যোগ, আপডেট এবং মুছে ফেলা উচিত। যেহেতু পরিচিতি সরবরাহকারী একটি applyBatch()-এ সমস্ত অপারেশন একটি একক ট্রানজ্যাকশনে সম্পাদন করে, তাই আপনার পরিবর্তনগুলি কখনই পরিচিতি রিপোজিটরিকে একটি অসঙ্গতিপূর্ণ অবস্থায় ছেড়ে যাবে না। ব্যাচ মডিফিকেশন একই সাথে র কন্ট্যাক্ট ও তার বিস্তারিত ডেটা যোগ করার সুবিধা প্রদান করে।

মনে রাখবেন: একটি র কন্ট্যাক্ট পরিবর্তন করতে, আপনার অ্যাপে পরিবর্তন ম্যানেজ করার পরিবর্তে ডিভাইসের কন্ট্যাক্ট অ্যাপ্লিকেশনে ইনটেন্ট পাঠানোর কথা বিবেচনা করুন। এটি করার পদ্ধতি সম্পর্কে আরও বিস্তারিত বিবরণ ইনটেন্টের মাধ্যমে পুনরুদ্ধার এবং পরিবর্তন বিভাগে দেওয়া আছে।

ইল্ড পয়েন্ট

অনেকগুলি অপারেশন সহ ব্যাচ মডিফিকেশন অন্যান্য প্রসেস ব্লক করতে পারে, যার ফলে ব্যবহারকারীর সামগ্রিক অভিজ্ঞতা খারাপ হয়। আপনি যত কম সম্ভব আলাদা আলাদা তালিকায় যেসব পরিবর্তন করতে চান, সেগুলি সাজাতে এবং একই সাথে সিস্টেমকে ব্লক করা থেকে আটকাতে, আপনাকে এক বা একাধিক অপারেশনের জন্য ইল্ড পয়েন্ট সেট করতে হবে। ইল্ড পয়েন্ট হল একটি ContentProviderOperation অবজেক্ট যার isYieldAllowed() ভ্যালু true-এ সেট করা আছে। পরিচিতি সরবরাহকারী ইল্ড পয়েন্টের সম্মুখীন হলে, এটি অন্যান্য প্রসেস চালানোর জন্য এর কাজ পজ করে এবং বর্তমান ট্রানজ্যাকশন বন্ধ করে দেয়। প্রোভাইডার আবার শুরু করলে, এটি ArrayList-এ পরবর্তী অপারেশন চালিয়ে যায় এবং নতুন ট্রানজ্যাকশন শুরু করে।

ইল্ড পয়েন্টের ফলে applyBatch()-এ প্রতি কলে একাধিক ট্রানজ্যাকশন হয়। এই কারণে, সম্পর্কিত সারির সেটের জন্য শেষ অপারেশনে আপনাকে ইল্ড পয়েন্ট সেট করতে হবে। যেমন, কোনও সেটের শেষ অপারেশনের জন্য আপনাকে ইল্ড পয়েন্ট সেট করতে হবে যা একটি র কন্ট্যাক্ট সারি এবং এর সাথে সম্পর্কিত ডেটা সারি যোগ করে অথবা কোনও একটি কন্ট্যাক্টের সাথে সম্পর্কিত সারির সেটের শেষ অপারেশন।

ইল্ড পয়েন্ট হল অ্যাটমিক অপারেশনের ইউনিট। দুটি ইল্ড পয়েন্টের মধ্যে সব অ্যাক্সেস একক ইউনিট হিসেবে হয় সফল হবে অথবা ব্যর্থ হবে। আপনি কোনও ইল্ড পয়েন্ট সেট না করলে, সবচেয়ে ছোট অ্যাটমিক অপারেশন হল অপারেশনের সম্পূর্ণ ব্যাচ। আপনি ইল্ড পয়েন্ট ব্যবহার করলে, সিস্টেমের পারফর্ম্যান্স যাতে খারাপ না হয় তার জন্য অপারেশন বন্ধ করতে পারবেন এবং একই সাথে, অপারেশনের সাবসেট অ্যাটমিক কিনা তা নিশ্চিত করতে পারবেন।

পরিবর্তন সংক্রান্ত ব্যাক রেফারেন্স

আপনি যখন একটি নতুন র কন্ট্যাক্ট সারি এবং এর সাথে সম্পর্কিত ডেটা সারিকে ContentProviderOperation অবজেক্টের সেট হিসেবে যোগ করছেন, তখন আপনাকে ডেটা সারিকে র কন্ট্যাক্ট সারির সাথে লিঙ্ক করতে হবে। এর জন্য র কন্ট্যাক্টের _ID ভ্যালুকে RAW_CONTACT_ID ভ্যালু হিসেবে যোগ করতে হবে। তবে, ডেটা সারির জন্য ContentProviderOperation তৈরি করার সময় এই ভ্যালু উপলভ্য থাকে না, কারণ আপনি এখনও র কন্ট্যাক্ট সারির জন্য ContentProviderOperation প্রয়োগ করেননি। এই সমস্যার সমাধান করতে, ContentProviderOperation.Builder ক্লাসে withValueBackReference() পদ্ধতি আছে। এই পদ্ধতি আপনাকে আগের অপারেশনের ফলাফলের সাথে একটি কলাম যোগ বা পরিবর্তন করতে অনুমতি দেয়।

withValueBackReference() পদ্ধতিতে দুটি আর্গুমেন্ট আছে:

key
কী-ভ্যালু পেয়ারের কী। এই আর্গুমেন্টের ভ্যালু, আপনি যে টেবিলটি পরিবর্তন করছেন সেটির কলামের নাম হতে হবে।
previousResult
applyBatch() থেকে ContentProviderResult অবজেক্টের অ্যারেতে কোনও ভ্যালুর ০-ভিত্তিক ইনডেক্স। ব্যাচ অপারেশন প্রয়োগ করা হলে, প্রতিটি অপারেশনের ফলাফল, ফলাফলের অন্তর্বর্তী অ্যারেতে স্টোর করা হয়। previousResult ভ্যালু হল এইসব ফলাফলের মধ্যে একটির ইন্ডেক্স, যা key ভ্যালুর সাথে উদ্ধার ও স্টোর করা হয়। এটি আপনাকে একটি নতুন র কন্ট্যাক্ট রেকর্ড যোগ করতে এবং এর _ID ভ্যালু ফেরত পেতে দেয়, তারপর আপনি যখন একটি ContactsContract.Data সারি যোগ করেন তখন ভ্যালুতে একটি "ব্যাক রেফারেন্স" তৈরি করে।

আপনি প্রথমবার applyBatch() কল করলে, আপনার দেওয়া ContentProviderOperation অবজেক্টের ArrayList-এর সাইজের সমান সাইজ সহ সম্পূর্ণ ফলাফল অ্যারে তৈরি করা হয়। তবে, ফলাফল অ্যারের সব এলিমেন্ট null-এ সেট করা থাকে এবং আপনি যদি এমন কোনও অপারেশনের ফলাফলের ব্যাক রেফারেন্স করার চেষ্টা করেন যা এখনও প্রয়োগ করা হয়নি, withValueBackReference() তাহলে Exception থ্রো করে।

নিচের স্নিপেট থেকে জানা যাবে যে কীভাবে ব্যাচে নতুন র কন্ট্যাক্ট ও ডেটা যোগ করতে হয়। এতে এমন কোড থাকে যা ইল্ড পয়েন্ট তৈরি করে এবং ব্যাক রেফারেন্স ব্যবহার করে।

প্রথম স্নিপেট UI থেকে পরিচিতির ডেটা ফিরিয়ে আনে। এই পর্যায়ে, ব্যবহারকারী ইতিমধ্যেই সেই অ্যাকাউন্ট বেছে নিয়েছেন যার জন্য নতুন র কন্ট্যাক্ট যোগ করতে হবে।

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]

জাভা

// 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())

জাভা

    /*
     * 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());

এরপর, কোডটি ডিসপ্লে নাম, ফোন এবং ইমেল সারির জন্য ডেটা সারি তৈরি করে।

প্রতিটি অপারেশন বিল্ডার অবজেক্ট withValueBackReference() ব্যবহার করে RAW_CONTACT_ID পাওয়ার জন্য। রেফারেন্সটি প্রথম অপারেশন থেকে 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())

জাভা

    // 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")
    }
}

জাভা

    // 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 অবজেক্ট তৈরি করুন। কন্টেন্ট URI-এর জন্য, RawContacts.CONTENT_URI ব্যবহার করুন এবং এর সাথে র কন্ট্যাক্টের _ID যোগ করুন।
  3. ContentProviderOperation.Builder অবজেক্টের জন্য, withValue() কল করুন যাতে VERSION কলামের সাথে আপনার এইমাত্র পাওয়া ভার্সন নম্বরের তুলনা করা যায়।
  4. একই ContentProviderOperation.Builder-এর জন্য, withExpectedCount() কল করুন যাতে নিশ্চিত করা যায় যে এই অ্যাসারশন দ্বারা শুধুমাত্র একটি সারি পরীক্ষা করা হয়েছে।
  5. ContentProviderOperation অবজেক্ট তৈরি করতে build() কল করুন, তারপর এই অবজেক্টকে ArrayList-এর প্রথম অবজেক্ট হিসেবে যোগ করুন যা আপনি applyBatch()-এ পাস করেন।
  6. ব্যাচ ট্রানজ্যাকশন প্রয়োগ করুন।

আপনি র কন্ট্যাক্ট সারিটি পড়ার সময় এবং এটি পরিবর্তন করার চেষ্টার সময়ের মধ্যে অন্য কোনও অপারেশনের মাধ্যমে সারিটি আপডেট করা হলে, "assert" ContentProviderOperation ব্যর্থ হবে এবং অপারেশনের পুরো ব্যাচটি বাতিল করা হবে। তারপর আপনি ব্যাচটি আবার চেষ্টা করার জন্য বেছে নিতে পারেন অথবা অন্য কোনও অ্যাকশন নিতে পারেন।

নিম্নলিখিত স্নিপেট থেকে বোঝা যায় যে কীভাবে একটি "assert" ContentProviderOperation তৈরি করতে হয়, CursorLoader ব্যবহার করে একটি র কন্ট্যাক্ট কোয়েরি করার পরে:

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
}

জাভা

/*
 * 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
    }

ইনটেন্ট সহ রিট্রিভাল ও পরিবর্তন

ডিভাইসের পরিচিতি অ্যাপ্লিকেশনে ইনটেন্ট পাঠানোর মাধ্যমে আপনি পরোক্ষভাবে পরিচিতি প্রদানকারী অ্যাক্সেস করতে পারবেন। ইনটেন্ট ডিভাইসের পরিচিতি অ্যাপ্লিকেশন UI শুরু করে, যেখানে ব্যবহারকারীরা পরিচিতি-সম্পর্কিত কাজ করতে পারেন। এই ধরনের অ্যাক্সেস থাকলে, ব্যবহারকারী এগুলি করতে পারবেন:

  • তালিকা থেকে কোনও পরিচিতি বেছে নিন এবং পরবর্তী কাজের জন্য আপনার অ্যাপে এটি ফিরিয়ে আনুন।
  • আগে থেকে থাকা পরিচিতির ডেটা এডিট করুন।
  • তার যেকোনও অ্যাকাউন্টের জন্য একটি নতুন র কন্ট্যাক্ট যোগ করুন।
  • একটি পরিচিতি বা পরিচিতির ডেটা মুছে দিন।

ব্যবহারকারী ডেটা যোগ বা আপডেট করলে, আপনি প্রথমে ডেটা সংগ্রহ করে ইনটেন্টের অংশ হিসেবে তা পাঠাতে পারেন।

ডিভাইসের পরিচিতি অ্যাপ্লিকেশনের মাধ্যমে পরিচিতি সরবরাহকারী অ্যাক্সেস করার জন্য আপনি ইনটেন্ট ব্যবহার করলে, আপনাকে সরবরাহকারী অ্যাক্সেস করার জন্য নিজের UI বা কোড লিখতে হবে না। এছাড়াও, আপনাকে প্রোভাইডারের ডেটা পড়া বা লেখার জন্য অনুমতি চাইতে হবে না। ডিভাইসের পরিচিতি অ্যাপ্লিকেশন আপনাকে কোনও পরিচিতির জন্য রিড পার্মিশন প্রতিনিধি হিসেবে দিতে পারে এবং আপনি অন্য অ্যাপ্লিকেশনের মাধ্যমে প্রোভাইডারে পরিবর্তন করছেন বলে, আপনার কাছে রাইট পার্মিশন থাকতে হবে না।

প্রোভাইডার অ্যাক্সেস করার জন্য ইনটেন্ট পাঠানোর সাধারণ প্রসেস কন্টেন্ট প্রোভাইডার সংক্রান্ত প্রাথমিক তথ্য গাইডের "ইনটেন্টের মাধ্যমে ডেটা অ্যাক্সেস" বিভাগে বিস্তারিতভাবে বর্ণনা করা হয়েছে। উপলভ্য টাস্কের জন্য আপনি যে অ্যাকশন, MIME-এর প্রকার ও ডেটা ভ্যালু ব্যবহার করেন, সেগুলি সারণী ৪-এ সংক্ষেপে দেখানো হয়েছে, যেখানে putExtra()-এর সাথে আপনি যে অতিরিক্ত ভ্যালু ব্যবহার করতে পারবেন, সেগুলি ContactsContract.Intents.Insert-এর রেফারেন্স ডকুমেন্টেশনে তালিকাভুক্ত করা হয়েছে:

টেবিল ৪. পরিচিতি সরবরাহকারী ইনটেন্ট।

টাস্ক অ্যাকশন ডেটা MIME-এর প্রকার নোট
তালিকা থেকে কোনও পরিচিতি বেছে নেওয়া ACTION_PICK এর মধ্যে একটি:
  • Contacts.CONTENT_URI, যা পরিচিতির তালিকা দেখায়।
  • Phone.CONTENT_URI, যা র কন্ট্যাক্টের জন্য ফোন নম্বরের তালিকা দেখায়।
  • StructuredPostal.CONTENT_URI, যা র কন্ট্যাক্টের জন্য ডাক ঠিকানার তালিকা দেখায়।
  • Email.CONTENT_URI, যা র কন্ট্যাক্টের জন্য ইমেল আইডির তালিকা দেখায়।
ব্যবহার করা হয়নি আপনার দেওয়া কন্টেন্ট URI-এর ধরনের উপর নির্ভর করে, র কন্ট্যাক্টের তালিকা বা র কন্ট্যাক্ট থেকে পাওয়া ডেটার তালিকা দেখায়।

কল startActivityForResult(), যা বেছে নেওয়া সারির কন্টেন্ট URI ফিরিয়ে দেয়। URI-এর ফর্ম হল টেবিলের কন্টেন্ট URI যার সাথে সারির LOOKUP_ID যোগ করা আছে। আপনার অ্যাক্টিভিটি চলাকালীন ডিভাইসের পরিচিতি অ্যাপ এই কন্টেন্ট URI-কে রিড ও রাইট করার অনুমতি প্রদান করে। আরও বিবরণের জন্য কন্টেন্ট প্রোভাইডার সংক্রান্ত প্রাথমিক তথ্য গাইড দেখুন।

নতুন র কন্ট্যাক্ট যোগ করা Insert.ACTION N/A RawContacts.CONTENT_TYPE, এক সেট র কন্ট্যাক্টের জন্য MIME-এর প্রকার। ডিভাইসের পরিচিতি অ্যাপ্লিকেশনের পরিচিতি যোগ করুন স্ক্রিন দেখায়। ইনটেন্টে আপনার যোগ করা অতিরিক্ত ভ্যালু দেখানো হয়। startActivityForResult()-এর সাথে পাঠানো হলে, নতুন যোগ করা র কন্ট্যাক্টের কন্টেন্ট URI আপনার অ্যাক্টিভিটির onActivityResult() কলব্যাক পদ্ধতিতে Intent আর্গুমেন্টে, "data" ফিল্ডে ফেরত পাঠানো হয়। ভ্যালু পেতে, getData() কল করুন।
পরিচিতি এডিট করুন ACTION_EDIT পরিচিতির জন্য CONTENT_LOOKUP_URI। এডিটর অ্যাক্টিভিটি ব্যবহারকারীকে এই পরিচিতির সাথে সম্পর্কিত যেকোনও ডেটা এডিট করার অনুমতি দেবে। Contacts.CONTENT_ITEM_TYPE, একটি পরিচিতি। পরিচিতি অ্যাপ্লিকেশনে পরিচিতি এডিট করার স্ক্রিন দেখায়। ইনটেন্টে আপনার যোগ করা অতিরিক্ত ভ্যালু দেখানো হয়। ব্যবহারকারী এডিট সেভ করতে হয়ে গেছে বিকল্পে ক্লিক করলে, আপনার অ্যাক্টিভিটি আবার ফোরগ্রাউন্ডে ফিরে আসে।
এমন একটি পিকার দেখান যা ডেটাও যোগ করতে পারে। ACTION_INSERT_OR_EDIT N/A CONTENT_ITEM_TYPE এই ইনটেন্ট সবসময় পরিচিতি অ্যাপের পিকার স্ক্রিন দেখায়। ব্যবহারকারী এডিট করার জন্য কোনও পরিচিতি বেছে নিতে অথবা নতুন পরিচিতি যোগ করতে পারেন। ব্যবহারকারীর পছন্দ অনুযায়ী এডিট বা যোগ করার স্ক্রিন দেখা যায় এবং ইনটেন্টে আপনি যে অতিরিক্ত ডেটা পাস করেন তা দেখানো হয়। আপনার অ্যাপ যদি ইমেল বা ফোন নম্বরের মতো পরিচিতির ডেটা দেখায়, তাহলে ব্যবহারকারীকে আগে থেকে থাকা পরিচিতিতে ডেটা যোগ করার অনুমতি দিতে এই ইনটেন্ট ব্যবহার করুন। পরিচিতি,

মনে রাখবেন: এই ইনটেন্টের অতিরিক্ত অংশে নামের ভ্যালু পাঠানোর প্রয়োজন নেই, কারণ ব্যবহারকারী সবসময় আগে থেকে থাকা নাম বেছে নেন অথবা নতুন নাম যোগ করেন। এছাড়াও, আপনি কোনও নাম পাঠালে এবং ব্যবহারকারী সেটি এডিট করতে চাইলে, পরিচিতি অ্যাপ আপনার পাঠানো নামটি দেখাবে এবং আগের নামটি ওভাররাইট করে দেবে। ব্যবহারকারী এটি লক্ষ্য না করে এডিট সেভ করে ফেললে, পুরনো ভ্যালু মুছে যায়।

ডিভাইসের পরিচিতি অ্যাপ আপনাকে কোনও র কন্ট্যাক্ট বা তার কোনও ডেটা ইনটেন্টের মাধ্যমে মুছতে দেয় না। পরিবর্তে, র কন্ট্যাক্ট মুছতে, 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)

জাভা

// 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-এর সাথে লিঙ্ক করা নেই, সেটি ডিভাইসের পরিচিতি অ্যাপ্লিকেশনে দেখা যাবে না এবং এর ফলে সিঙ্ক অ্যাডাপ্টারে সমস্যা হতে পারে।
শুধুমাত্র আপনার মালিকানাধীন র কন্ট্যাক্টের ডেটা পরিবর্তন করুন।
মনে রাখবেন যে পরিচিতি সরবরাহকারী সাধারণত বিভিন্ন ধরনের অ্যাকাউন্ট/অনলাইন পরিষেবা থেকে ডেটা ম্যানেজ করে। আপনাকে নিশ্চিত করতে হবে যে আপনার অ্যাপ্লিকেশন শুধুমাত্র আপনার মালিকানাধীন সারির ডেটা পরিবর্তন বা মুছে ফেলে এবং এটি শুধুমাত্র আপনার নিয়ন্ত্রণে থাকা অ্যাকাউন্টের ধরন এবং নাম সহ ডেটা যোগ করে।
কর্তৃপক্ষ, কন্টেন্ট URI, URI পাথ, কলামের নাম, MIME-এর প্রকার এবং TYPE ভ্যালুর জন্য ContactsContract এবং এর সাবক্লাসে সংজ্ঞায়িত ধ্রুবকগুলি সবসময় ব্যবহার করুন।
এইসব কনস্ট্যান্ট ব্যবহার করলে আপনি ভুল এড়াতে পারবেন। কোনও কনস্ট্যান্টের ব্যবহার বন্ধ করা হলে, কম্পাইলার সতর্কতার মাধ্যমে আপনাকে জানানো হবে।

কাস্টম ডেটা সারি

আপনার নিজস্ব কাস্টম MIME-এর প্রকার তৈরি ও ব্যবহার করে, আপনি ContactsContract.Data টেবিলে আপনার নিজস্ব ডেটা সারি যোগ, এডিট, মুছে ফেলতে এবং পুনরুদ্ধার করতে পারবেন। আপনার সারিগুলি ContactsContract.DataColumns-এ সংজ্ঞায়িত কলাম ব্যবহার করার মধ্যে সীমাবদ্ধ, যদিও আপনি ডিফল্ট কলামের নামের সাথে আপনার নিজস্ব ধরন-নির্দিষ্ট কলামের নাম ম্যাপ করতে পারেন। ডিভাইসের পরিচিতি অ্যাপ্লিকেশনে, আপনার সারির ডেটা দেখানো হয় কিন্তু এডিট বা মুছে ফেলা যায় না এবং ব্যবহারকারীরা অতিরিক্ত ডেটা যোগ করতে পারেন না। ব্যবহারকারীদের আপনার কাস্টম ডেটা সারি পরিবর্তন করার অনুমতি দিতে, আপনাকে অবশ্যই আপনার নিজস্ব অ্যাপ্লিকেশনে একটি এডিটর অ্যাক্টিভিটি প্রদান করতে হবে।

আপনার কাস্টম ডেটা দেখাতে, একটি contacts.xml ফাইল প্রদান করুন যাতে একটি <ContactsAccountType> এলিমেন্ট এবং এর এক বা একাধিক <ContactsDataKind> চাইল্ড এলিমেন্ট থাকে। এটি <ContactsDataKind> element বিভাগে আরও বিস্তারিতভাবে বর্ণনা করা হয়েছে।

কাস্টম MIME-এর প্রকার সম্পর্কে আরও জানতে, কন্টেন্ট প্রোভাইডার তৈরি করুন নির্দেশিকা পড়ুন।

পরিচিতি সরবরাহকারী সিঙ্ক অ্যাডাপ্টার

পরিচিতি সরবরাহকারীকে বিশেষভাবে ডিজাইন করা হয়েছে যাতে কোনও ডিভাইস ও অনলাইন পরিষেবার মধ্যে পরিচিতি ডেটার সিঙ্ক করা ম্যানেজ করা যায়। এর ফলে ব্যবহারকারীরা নতুন ডিভাইসে আগে থেকে থাকা ডেটা ডাউনলোড করতে এবং নতুন অ্যাকাউন্টে আগে থেকে থাকা ডেটা আপলোড করতে পারবেন। এছাড়াও, সিঙ্ক করার ফলে ব্যবহারকারীর কাছে লেটেস্ট ডেটা থাকে, ডেটা যেখান থেকেই যোগ বা পরিবর্তন করা হোক না কেন। সিঙ্ক করার আরেকটি সুবিধা হল, ডিভাইস নেটওয়ার্কের সাথে কানেক্ট করা না থাকলেও এটি পরিচিতির ডেটা উপলভ্য করে।

আপনি বিভিন্ন উপায়ে সিঙ্ক্রোনাইজেশন প্রয়োগ করতে পারলেও, Android সিস্টেম একটি প্লাগ-ইন সিঙ্ক্রোনাইজেশন ফ্রেমওয়ার্ক প্রদান করে যা নিম্নলিখিত টাস্ক অটোমেট করে:

  • নেটওয়ার্কের উপলভ্যতা চেক করা হচ্ছে।
  • ব্যবহারকারীর পছন্দ অনুযায়ী সিঙ্ক্রোনাইজেশন শিডিউল ও এক্সিকিউট করা।
  • বন্ধ হয়ে যাওয়া সিঙ্ক আবার চালু করা হচ্ছে।

এই ফ্রেমওয়ার্ক ব্যবহার করতে, আপনাকে সিঙ্ক অ্যাডাপ্টার প্লাগ-ইন দিতে হবে। প্রতিটি সিঙ্ক অ্যাডাপ্টার একটি পরিষেবা এবং কন্টেন্ট প্রোভাইডারের জন্য অনন্য, তবে একই পরিষেবার জন্য একাধিক অ্যাকাউন্টের নাম ম্যানেজ করতে পারে। এছাড়াও, ফ্রেমওয়ার্ক একই পরিষেবা ও প্রদানকারীর জন্য একাধিক সিঙ্ক অ্যাডাপ্টার ব্যবহারের অনুমতি দেয়।

সিঙ্ক অ্যাডাপ্টার ক্লাস ও ফাইল

আপনি AbstractThreadedSyncAdapter-এর সাবক্লাস হিসেবে সিঙ্ক অ্যাডাপ্টার প্রয়োগ করেন এবং Android অ্যাপ্লিকেশনের অংশ হিসেবে এটি ইনস্টল করেন। সিস্টেম আপনার অ্যাপ্লিকেশন ম্যানিফেস্টের এলিমেন্ট এবং ম্যানিফেস্টের মাধ্যমে নির্দেশিত একটি বিশেষ XML ফাইল থেকে সিঙ্ক অ্যাডাপ্টার সম্পর্কে জানতে পারে। XML ফাইলটি অনলাইন পরিষেবার জন্য অ্যাকাউন্টের ধরন এবং কন্টেন্ট প্রোভাইডারের জন্য অথরিটি নির্ধারণ করে, যা একসাথে অ্যাডাপ্টারকে অনন্যভাবে শনাক্ত করে। সিঙ্ক অ্যাডাপ্টার অ্যাক্টিভ হয় না যতক্ষণ না ব্যবহারকারী সিঙ্ক অ্যাডাপ্টারের অ্যাকাউন্টের ধরনের জন্য অ্যাকাউন্ট যোগ করেন এবং সিঙ্ক অ্যাডাপ্টার যে কন্টেন্ট প্রোভাইডারের সাথে সিঙ্ক করে তার জন্য সিঙ্ক্রোনাইজেশন চালু করেন। সেই সময়, সিস্টেম অ্যাডাপ্টার ম্যানেজ করা শুরু করে, কন্টেন্ট প্রোভাইডার ও সার্ভারের মধ্যে সিঙ্ক করার জন্য প্রয়োজন অনুযায়ী এটিকে কল করে।

মনে রাখবেন: সিঙ্ক অ্যাডাপ্টারের শনাক্তকরণের অংশ হিসেবে অ্যাকাউন্টের ধরন ব্যবহার করলে, সিস্টেম একই সংস্থার বিভিন্ন পরিষেবা অ্যাক্সেস করা সিঙ্ক অ্যাডাপ্টারগুলিকে শনাক্ত করতে এবং একসাথে গ্রুপ করতে পারে। যেমন, Google অনলাইন পরিষেবার জন্য সিঙ্ক অ্যাডাপ্টারের সবকটির একই অ্যাকাউন্টের ধরন com.google আছে। ব্যবহারকারীরা তাদের ডিভাইসে Google অ্যাকাউন্ট যোগ করলে, Google পরিষেবার জন্য ইনস্টল করা সব সিঙ্ক অ্যাডাপ্টার একসাথে তালিকাভুক্ত করা হয়; তালিকাভুক্ত প্রতিটি সিঙ্ক অ্যাডাপ্টার ডিভাইসে একটি ভিন্ন কন্টেন্ট প্রোভাইডারের সাথে সিঙ্ক করে।

যেহেতু বেশিরভাগ পরিষেবার ক্ষেত্রে ডেটা অ্যাক্সেস করার আগে ব্যবহারকারীদের পরিচয় যাচাই করতে হয়, তাই Android সিস্টেম একটি যাচাইকরণ ফ্রেমওয়ার্ক অফার করে যা সিঙ্ক অ্যাডাপ্টার ফ্রেমওয়ার্কের মতো এবং প্রায়ই এর সাথে একসাথে ব্যবহার করা হয়। যাচাইকরণ ফ্রেমওয়ার্ক প্লাগ-ইন যাচাইকারী ব্যবহার করে যা AbstractAccountAuthenticator-এর সাবক্লাস। একজন যাচাইকারী নিম্নলিখিত ধাপে ব্যবহারকারীর পরিচয় যাচাই করেন:

  1. ব্যবহারকারীর নাম, পাসওয়ার্ড বা একই ধরনের তথ্য (ব্যবহারকারীর ক্রেডেনশিয়াল) সংগ্রহ করে।
  2. পরিষেবায় ক্রেডেনশিয়াল পাঠায়
  3. পরিষেবার উত্তর পরীক্ষা করে।

পরিষেবা ক্রেডেনশিয়াল গ্রহণ করলে, যাচাইকারী পরে ব্যবহারের জন্য ক্রেডেনশিয়াল স্টোর করতে পারে। প্লাগ-ইন যাচাইকারী ফ্রেমওয়ার্কের কারণে, AccountManager যেকোনও যাচাইকারী টোকেন অ্যাক্সেস করার সুবিধা দিতে পারে, যা যাচাইকারী সমর্থন করে এবং প্রকাশ করার জন্য বেছে নেয়, যেমন OAuth2 যাচাইকারী টোকেন।

যাচাইকরণ বাধ্যতামূলক না হলেও, বেশিরভাগ পরিচিতি পরিষেবা এটি ব্যবহার করে। তবে, যাচাইকরণের জন্য আপনাকে Android যাচাইকরণ ফ্রেমওয়ার্ক ব্যবহার করতে হবে না।

সিঙ্ক অ্যাডাপ্টার প্রয়োগ করা

পরিচিতি সরবরাহকারীর জন্য সিঙ্ক অ্যাডাপ্টার প্রয়োগ করতে, আপনি একটি Android অ্যাপ্লিকেশন তৈরি করে শুরু করুন যার মধ্যে নিম্নলিখিতগুলি রয়েছে:

একটি Service কম্পোনেন্ট যা সিঙ্ক অ্যাডাপ্টারের সাথে বাইন্ড করার জন্য সিস্টেম থেকে আসা অনুরোধের উত্তর দেয়।
সিস্টেম যখন সিঙ্ক করতে চায়, তখন এটি পরিষেবার onBind() মেথডকে কল করে যাতে সিঙ্ক অ্যাডাপ্টারের জন্য IBinder পাওয়া যায়। এটি সিস্টেমকে অ্যাডাপ্টারের পদ্ধতিতে ক্রস-প্রসেস কল করার অনুমতি দেয়।
আসল সিঙ্ক অ্যাডাপ্টার, AbstractThreadedSyncAdapter-এর কংক্রিট সাবক্লাস হিসেবে প্রয়োগ করা হয়েছে।
এই ক্লাস সার্ভার থেকে ডেটা ডাউনলোড, ডিভাইস থেকে ডেটা আপলোড এবং সমস্যা সমাধানের কাজ করে। অ্যাডাপ্টারের মূল কাজ onPerformSync() পদ্ধতিতে করা হয়। এই ক্লাসটি অবশ্যই সিঙ্গলটন হিসাবে ইনস্ট্যান্টিয়েট করতে হবে।
Application-এর একটি সাবক্লাস।
এই ক্লাসটি সিঙ্ক অ্যাডাপ্টার সিঙ্গলটনের জন্য ফ্যাক্টরি হিসেবে কাজ করে। সিঙ্ক অ্যাডাপ্টার ইনস্ট্যান্টিয়েট করতে onCreate() পদ্ধতি ব্যবহার করুন এবং সিঙ্ক অ্যাডাপ্টারের পরিষেবার onBind() পদ্ধতিতে সিঙ্গলটন ফিরিয়ে দিতে একটি স্ট্যাটিক "গেটার" পদ্ধতি প্রদান করুন।
ঐচ্ছিক: একটি Service কম্পোনেন্ট যা ব্যবহারকারী যাচাইকরণের জন্য সিস্টেম থেকে আসা অনুরোধের উত্তর দেয়।
AccountManager যাচাইকরণ প্রসেস শুরু করার জন্য এই পরিষেবা চালু করে। পরিষেবার onCreate() পদ্ধতি একটি যাচাইকারী অবজেক্ট ইনস্ট্যান্টিয়েট করে। সিস্টেম যখন অ্যাপ্লিকেশনের সিঙ্ক অ্যাডাপ্টারের জন্য ব্যবহারকারীর অ্যাকাউন্ট যাচাই করতে চায়, তখন এটি পরিষেবার onBind() পদ্ধতি কল করে যাচাইকারীর জন্য IBinder পায়। এটি সিস্টেমকে প্রমাণীকরণকারীর পদ্ধতিতে ক্রস-প্রসেস কল করার অনুমতি দেয়..
ঐচ্ছিক: AbstractAccountAuthenticator-এর একটি কংক্রিট সাবক্লাস যা যাচাইকরণের জন্য অনুরোধ ম্যানেজ করে।
এই ক্লাস এমন পদ্ধতি প্রদান করে যা AccountManager সার্ভারের সাথে ব্যবহারকারীর ক্রেডেনশিয়াল যাচাই করার জন্য কল করে। ব্যবহার করা সার্ভার প্রযুক্তির উপর ভিত্তি করে, যাচাইকরণ প্রক্রিয়ার বিবরণ ব্যাপকভাবে পরিবর্তিত হয়। যাচাইকরণ সম্পর্কে আরও জানতে আপনার সার্ভার সফ্টওয়্যারের ডকুমেন্টেশন দেখুন।
XML ফাইল যা সিস্টেমে সিঙ্ক অ্যাডাপ্টার এবং যাচাইকরণকারীকে সংজ্ঞায়িত করে।
আগে বর্ণনা করা সিঙ্ক অ্যাডাপ্টার ও যাচাইকরণ পরিষেবা কম্পোনেন্ট অ্যাপ্লিকেশন ম্যানিফেস্টে <service> এলিমেন্টে সংজ্ঞায়িত করা আছে। এইসব এলিমেন্টে এমন <meta-data> চাইল্ড এলিমেন্ট থাকে যা সিস্টেমে নির্দিষ্ট ডেটা প্রদান করে:
  • সিঙ্ক অ্যাডাপ্টার পরিষেবার জন্য <meta-data> এলিমেন্ট XML ফাইল res/xml/syncadapter.xml-এ পয়েন্ট করে। পরিবর্তে, এই ফাইলটি ওয়েব পরিষেবার জন্য একটি URI নির্দিষ্ট করে যা পরিচিতি সরবরাহকারীর সাথে সিঙ্ক করা হবে, এবং ওয়েব পরিষেবার জন্য একটি অ্যাকাউন্টের ধরন।
  • ঐচ্ছিক: <meta-data> এলিমেন্টটি প্রমাণীকরণের জন্য XML ফাইল res/xml/authenticator.xml-কে নির্দেশ করে। পরিবর্তে, এই ফাইলটি এই প্রমাণীকরণকারী দ্বারা সমর্থিত অ্যাকাউন্টের ধরন এবং প্রমাণীকরণ প্রক্রিয়া চলাকালীন প্রদর্শিত UI রিসোর্সগুলি নির্দিষ্ট করে। এই এলিমেন্টে উল্লেখ করা অ্যাকাউন্টের ধরন সিঙ্ক অ্যাডাপ্টারের জন্য উল্লেখ করা অ্যাকাউন্টের ধরনের একই হতে হবে।

সোশ্যাল স্ট্রিম ডেটা

android.provider.ContactsContract.StreamItems এবং android.provider.ContactsContract.StreamItemPhotos টেবিল সামাজিক নেটওয়ার্ক থেকে আসা ডেটা পরিচালনা করে। আপনি এমন একটি সিঙ্ক অ্যাডাপ্টার লিখতে পারেন যা আপনার নিজস্ব নেটওয়ার্ক থেকে এই টেবিলে স্ট্রিম ডেটা যোগ করে অথবা আপনি এই টেবিল থেকে স্ট্রিম ডেটা পড়তে এবং আপনার নিজস্ব অ্যাপ্লিকেশনে এটি প্রদর্শন করতে পারেন অথবা দুটিই করতে পারেন। এইসব ফিচারের মাধ্যমে, আপনার সোশ্যাল নেটওয়ার্কিং পরিষেবা ও অ্যাপ্লিকেশন Android-এর সোশ্যাল নেটওয়ার্কিং অভিজ্ঞতার সাথে ইন্টিগ্রেট করা যেতে পারে।

সোশ্যাল স্ট্রিম টেক্সট

স্ট্রিম আইটেম সবসময় র কন্ট্যাক্টের সাথে যুক্ত থাকে। The android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID links to the _ID value for the raw contact. র কন্ট্যাক্টের অ্যাকাউন্টের ধরন ও অ্যাকাউন্টের নামও স্ট্রিম আইটেম সারিতে স্টোর করা হয়।

আপনার স্ট্রিম থেকে ডেটা নিম্নলিখিত কলামে স্টোর করুন:

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 Provider-এর আগের ভার্সনের সাথে ব্যাকওয়ার্ড কম্প্যাটিবিলিটির জন্য উপলভ্য, যা ফটো স্টোর করার জন্য ব্যবহার করা হয়। তবে, বর্তমান ভার্সনে ফটো স্টোর করার জন্য আপনার এই কলাম ব্যবহার করা উচিত নয়। পরিবর্তে, ফাইলে ফটো সেভ করতে android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID অথবা android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI (দুটিই নিচের পয়েন্টে বর্ণনা করা হয়েছে) ব্যবহার করুন। এই কলামে এখন ফটোর থাম্বনেল রয়েছে, যা পড়ার জন্য উপলভ্য।
android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID
র কন্ট্যাক্টের জন্য কোনও ফটোর সংখ্যাসূচক শনাক্তকারী। এই ভ্যালু কনস্ট্যান্টের সাথে যোগ করুন DisplayPhoto.CONTENT_URI যাতে একটি ফটো ফাইলের দিকে নির্দেশ করা কন্টেন্ট URI পাওয়া যায় এবং তারপর openAssetFileDescriptor() কল করে ফটো ফাইলের হ্যান্ডেল পান।
android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI
এই সারিতে দেখানো ফটোর জন্য সরাসরি ফটো ফাইলকে পয়েন্ট করে এমন কন্টেন্ট URI। ফটো ফাইলের হ্যান্ডেল পেতে এই URI-এর মাধ্যমে openAssetFileDescriptor()-এ কল করুন।

সোশ্যাল স্ট্রিম টেবিল ব্যবহার করা

এই সারণীগুলি Contacts Provider-এর অন্যান্য প্রধান সারণীর মতোই কাজ করে, তবে নিম্নলিখিত ব্যতিক্রমগুলি রয়েছে:

  • এইসব টেবিলের জন্য অতিরিক্ত অ্যাক্সেস সংক্রান্ত অনুমতি প্রয়োজন। সেগুলি থেকে পড়তে, আপনার অ্যাপ্লিকেশনের অবশ্যই android.Manifest.permission#READ_SOCIAL_STREAM অনুমতি থাকতে হবে৷ এগুলি পরিবর্তন করতে, আপনার অ্যাপ্লিকেশনের কাছে অবশ্যই android.Manifest.permission#WRITE_SOCIAL_STREAM অনুমতি থাকতে হবে।
  • android.provider.ContactsContract.StreamItems টেবিলের জন্য, প্রতিটি র কন্ট্যাক্টের জন্য সেভ করা সারির সংখ্যা সীমিত। এই সীমায় পৌঁছে গেলে, পরিচিতি সরবরাহকারী সবচেয়ে পুরনো android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP সহ সারি অটোমেটিক মুছে দিয়ে নতুন স্ট্রিম আইটেম সারির জন্য জায়গা তৈরি করে। সীমা জানতে, কন্টেন্ট URI android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI-তে কোয়েরি করুন। আপনি null-এ সেট করা কন্টেন্ট URI ছাড়া অন্য সব আর্গুমেন্ট ছেড়ে দিতে পারেন। কোয়েরি একটি সারি সহ কার্সর রিটার্ন করে, যার মধ্যে একটি কলাম থাকে android.provider.ContactsContract.StreamItems#MAX_ITEMS.

android.provider.ContactsContract.StreamItems.StreamItemPhotos ক্লাসটি android.provider.ContactsContract.StreamItemPhotos-এর একটি সাব-টেবিলকে সংজ্ঞায়িত করে, যাতে একটি একক স্ট্রিম আইটেমের জন্য ফটো সারি থাকে।

সোশ্যাল স্ট্রিম ইন্টার‍্যাকশন

পরিচিতি সরবরাহকারী দ্বারা পরিচালিত সোশ্যাল স্ট্রিম ডেটা, ডিভাইসের পরিচিতি অ্যাপ্লিকেশনের সাথে একযোগে, আপনার সোশ্যাল নেটওয়ার্কিং সিস্টেমকে বিদ্যমান পরিচিতির সাথে কানেক্ট করার একটি শক্তিশালী উপায় অফার করে। নিম্নলিখিত ফিচারগুলি উপলভ্য:

  • সিঙ্ক অ্যাডাপ্টারের মাধ্যমে আপনার সোশ্যাল নেটওয়ার্কিং পরিষেবা পরিচিতি সরবরাহকারীর সাথে সিঙ্ক করে, আপনি কোনও ব্যবহারকারীর পরিচিতির সাম্প্রতিক অ্যাক্টিভিটি ফিরিয়ে আনতে এবং পরে ব্যবহার করার জন্য android.provider.ContactsContract.StreamItems এবং android.provider.ContactsContract.StreamItemPhotos টেবিলে সেভ করতে পারবেন।
  • নিয়মিত সিঙ্ক করার পাশাপাশি, ব্যবহারকারী কোনও পরিচিতি দেখার জন্য বেছে নিলে, অতিরিক্ত ডেটা উদ্ধার করার জন্য আপনি সিঙ্ক অ্যাডাপ্টার ট্রিগার করতে পারবেন। এটি আপনার সিঙ্ক অ্যাডাপ্টারকে পরিচিতির জন্য হাই-রেজোলিউশন ফটো এবং সবচেয়ে সাম্প্রতিক স্ট্রিম আইটেমগুলি ফিরিয়ে আনতে দেয়।
  • ডিভাইসের পরিচিতি অ্যাপ্লিকেশন এবং পরিচিতি সরবরাহকারীর সাথে একটি বিজ্ঞপ্তি রেজিস্টার করে, আপনি কোনও পরিচিতি দেখার সময় একটি ইনটেন্ট পেতে পারেন এবং সেই সময়ে আপনার পরিষেবা থেকে পরিচিতির স্ট্যাটাস আপডেট করতে পারেন। এই পদ্ধতিটি সিঙ্ক অ্যাডাপ্টারের মাধ্যমে সম্পূর্ণ সিঙ্ক করার চেয়ে দ্রুত হতে পারে এবং কম ব্যান্ডউইথ ব্যবহার করতে পারে।
  • ব্যবহারকারীরা ডিভাইসের পরিচিতি অ্যাপ্লিকেশনে পরিচিতি দেখার সময় আপনার সামাজিক নেটওয়ার্কিং পরিষেবাতে একটি পরিচিতি যোগ করতে পারেন। আপনি "পরিচিতিকে আমন্ত্রণ জানান" ফিচারের মাধ্যমে এটি চালু করেন, যা আপনি এমন একটি অ্যাক্টিভিটির সাথে চালু করেন যা আপনার নেটওয়ার্কে আগে থেকে থাকা পরিচিতিকে যোগ করে এবং একটি XML ফাইল যা ডিভাইসের পরিচিতি অ্যাপ্লিকেশন এবং পরিচিতি প্রদানকারীকে আপনার অ্যাপ্লিকেশনের বিবরণ প্রদান করে।

পরিচিতি সরবরাহকারীর সাথে স্ট্রিম আইটেমের নিয়মিত সিঙ্ক্রোনাইজেশন অন্যান্য সিঙ্ক্রোনাইজেশনের মতোই। সিঙ্ক্রোনাইজেশন সম্পর্কে আরও জানতে, পরিচিতি সরবরাহকারী সিঙ্ক অ্যাডাপ্টার বিভাগটি দেখুন। বিজ্ঞপ্তি রেজিস্টার করা এবং পরিচিতিদের আমন্ত্রণ জানানোর বিষয়টি পরবর্তী দুটি বিভাগে কভার করা হয়েছে।

সোশ্যাল নেটওয়ার্কিং ভিউ ম্যানেজ করার জন্য রেজিস্টার করা হচ্ছে

ব্যবহারকারী আপনার সিঙ্ক অ্যাডাপ্টারের মাধ্যমে ম্যানেজ করা কোনও পরিচিতি দেখলে বিজ্ঞপ্তি পাওয়ার জন্য আপনার সিঙ্ক অ্যাডাপ্টার রেজিস্টার করতে:

  1. আপনার প্রোজেক্টের res/xml/ ডিরেক্টরিতে contacts.xml নামের একটি ফাইল তৈরি করুন। আপনার কাছে এই ফাইলটি আগে থেকেই থাকলে, আপনি এই ধাপটি এড়িয়ে যেতে পারেন।
  2. এই ফাইলে, এলিমেন্ট যোগ করুন <ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">. এই এলিমেন্ট আগে থেকেই থাকলে, আপনি এই ধাপটি এড়িয়ে যেতে পারেন।
  3. ব্যবহারকারী ডিভাইসের পরিচিতি অ্যাপ্লিকেশনে কোনও পরিচিতির বিবরণ পৃষ্ঠা খুললে বিজ্ঞপ্তি পায় এমন একটি পরিষেবা রেজিস্টার করতে, এলিমেন্টে viewContactNotifyService="serviceclass" অ্যাট্রিবিউট যোগ করুন, যেখানে serviceclass হল পরিষেবার সম্পূর্ণ-যোগ্য ক্লাসনেম যা ডিভাইসের পরিচিতি অ্যাপ্লিকেশন থেকে ইনটেন্ট গ্রহণ করবে। বিজ্ঞপ্তি পরিষেবার জন্য, এমন একটি ক্লাস ব্যবহার করুন যা IntentService-কে এক্সটেন্ড করে, যাতে পরিষেবাটি ইনটেন্ট গ্রহণ করতে পারে। ইনকামিং ইনটেন্টের ডেটাতে ব্যবহারকারীর ক্লিক করা র কন্ট্যাক্টের কন্টেন্ট URI থাকে। বিজ্ঞপ্তি পরিষেবা থেকে, আপনি র কন্ট্যাক্টের ডেটা আপডেট করার জন্য আপনার সিঙ্ক অ্যাডাপ্টারে বাইন্ড করতে এবং তারপরে কল করতে পারেন।

ব্যবহারকারী কোনও স্ট্রিম আইটেম বা ফটো অথবা দুটিতেই ক্লিক করলে, কল করার জন্য কোনও অ্যাক্টিভিটি রেজিস্টার করতে:

  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> এলিমেন্ট বিভাগে আরও বিস্তারিতভাবে বর্ণনা করা হয়েছে।

ইনকামিং ইনটেন্টে ব্যবহারকারীর ক্লিক করা আইটেম বা ফটোর কন্টেন্ট URI থাকে। টেক্সট আইটেম ও ফটোর জন্য আলাদা অ্যাক্টিভিটি রাখতে, একই ফাইলে দুটি অ্যাট্রিবিউটই ব্যবহার করুন।

আপনার সোশ্যাল নেটওয়ার্কিং পরিষেবার সাথে ইন্টার‌্যাক্ট করা

ব্যবহারকারীদের আপনার সোশ্যাল নেটওয়ার্কিং সাইটে কোনও পরিচিতিকে আমন্ত্রণ জানানোর জন্য ডিভাইসের পরিচিতি অ্যাপ্লিকেশন ছেড়ে যেতে হবে না। পরিবর্তে, আপনি ডিভাইসের পরিচিতি অ্যাপকে আপনার কোনও একটি অ্যাক্টিভিটিতে পরিচিতিকে আমন্ত্রণ জানানোর জন্য একটি ইনটেন্ট পাঠাতে বলতে পারেন। এটি সেট-আপ করতে:

  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 ফাইলে XML এলিমেন্ট আছে যা আপনার সিঙ্ক অ্যাডাপ্টার ও অ্যাপ্লিকেশনের সাথে পরিচিতি অ্যাপ্লিকেশন ও পরিচিতি সরবরাহকারীর ইন্টার‍্যাকশন নিয়ন্ত্রণ করে। এইসব এলিমেন্ট নিম্নলিখিত বিভাগে বর্ণনা করা হয়েছে।

<যোগাযোগের অ্যাকাউন্টের ধরণ> উপাদান

<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 কম্পোনেন্ট এবং UI লেবেল ঘোষণা করে যা ব্যবহারকারীদের তাদের পরিচিতিদের মধ্যে একজনকে সোশ্যাল নেটওয়ার্কে আমন্ত্রণ জানাতে, তাদের সোশ্যাল নেটওয়ার্কিং স্ট্রিমগুলির মধ্যে একটি আপডেট হলে ব্যবহারকারীদের বিজ্ঞপ্তি দিতে এবং আরও অনেক কিছু করতে দেয়।

মনে রাখবেন যে <ContactsAccountType>-এর অ্যাট্রিবিউটের জন্য অ্যাট্রিবিউট প্রিফিক্স android: প্রয়োজন নেই।

অ্যাট্রিবিউট:

inviteContactActivity
ব্যবহারকারী ডিভাইসের পরিচিতি অ্যাপ্লিকেশন থেকে কানেকশন যোগ করুন বিকল্প বেছে নিলে, আপনার অ্যাপ্লিকেশনে যে অ্যাক্টিভিটি অ্যাক্টিভেট করতে চান, তার সম্পূর্ণ-যোগ্য ক্লাস নাম।
inviteContactActionLabel
inviteContactActivity-এ উল্লেখ করা অ্যাক্টিভিটির জন্য দেখানো টেক্সট স্ট্রিং, কানেকশন যোগ করুন মেনুতে। যেমন, আপনি "আমার নেটওয়ার্কে ফলো করুন" স্ট্রিং ব্যবহার করতে পারেন। এই লেবেলের জন্য আপনি স্ট্রিং রিসোর্স শনাক্তকারী ব্যবহার করতে পারেন।
viewContactNotifyService
আপনার অ্যাপ্লিকেশনের কোনও পরিষেবার সম্পূর্ণ-যোগ্য ক্লাস নাম যা ব্যবহারকারী কোনও পরিচিতি দেখলে বিজ্ঞপ্তি পাবে। এই বিজ্ঞপ্তি ডিভাইসের পরিচিতি অ্যাপ্লিকেশন পাঠায়; এটি আপনার অ্যাপ্লিকেশনকে ডেটা-ইনটেনসিভ অপারেশন স্থগিত করার অনুমতি দেয় যতক্ষণ না সেগুলির প্রয়োজন হয়। যেমন, আপনার অ্যাপ্লিকেশন এই বিজ্ঞপ্তির উত্তর দিতে পারে পরিচিতির হাই-রেজোলিউশন ফটো এবং সবচেয়ে সাম্প্রতিক সোশ্যাল স্ট্রিম আইটেম পড়ে ও দেখিয়ে। এই ফিচারটি সোশ্যাল স্ট্রিম ইন্টার‍্যাকশন বিভাগে আরও বিস্তারিতভাবে বর্ণনা করা হয়েছে।
viewGroupActivity
আপনার অ্যাপ্লিকেশনে কোনও অ্যাক্টিভিটির সম্পূর্ণ-যোগ্য ক্লাস নাম যা গ্রুপের তথ্য দেখাতে পারে। ব্যবহারকারী ডিভাইসের পরিচিতি অ্যাপ্লিকেশনে গ্রুপ লেবেলে ক্লিক করলে, এই অ্যাক্টিভিটির জন্য UI দেখানো হয়।
viewGroupActionLabel
UI কন্ট্রোলের জন্য পরিচিতি অ্যাপ্লিকেশন যে লেবেল দেখায়, যার মাধ্যমে ব্যবহারকারী আপনার অ্যাপ্লিকেশনে গ্রুপ দেখতে পান।

এই অ্যাট্রিবিউটের জন্য স্ট্রিং রিসোর্স শনাক্তকারী অনুমোদিত।

viewStreamItemActivity
আপনার অ্যাপ্লিকেশনের কোনও অ্যাক্টিভিটির সম্পূর্ণ-যোগ্য ক্লাস নাম যা ডিভাইসের পরিচিতি অ্যাপ্লিকেশন চালু করে যখন ব্যবহারকারী কোনও র কন্ট্যাক্টের জন্য স্ট্রিম আইটেমে ক্লিক করেন।
viewStreamItemPhotoActivity
আপনার অ্যাপ্লিকেশনের কোনও অ্যাক্টিভিটির সম্পূর্ণ-যোগ্য ক্লাস নাম যা ডিভাইসের পরিচিতি অ্যাপ্লিকেশন চালু করে যখন ব্যবহারকারী র কন্ট্যাক্টের জন্য স্ট্রিম আইটেমে কোনও ফটোতে ক্লিক করেন।

<ContactsDataKind> এলিমেন্ট

<ContactsDataKind> এলিমেন্ট, পরিচিতি অ্যাপ্লিকেশনের UI-তে আপনার অ্যাপ্লিকেশনের কাস্টম ডেটা রো-এর ডিসপ্লে কন্ট্রোল করে। এটির সিনট্যাক্স নিচে দেওয়া হল:

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

এতে রয়েছে:

<ContactsAccountType>

বিবরণ:

র কন্ট্যাক্টের বিবরণের অংশ হিসেবে কাস্টম ডেটা রোয়ের কন্টেন্ট দেখানোর জন্য পরিচিতি অ্যাপ্লিকেশনকে নির্দেশ দিতে এই এলিমেন্ট ব্যবহার করুন। <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.CommonDataKinds.GroupMembership MIME টাইপ ব্যবহার করে ContactsContract.Data টেবিলে স্টোর করা হয়।

আপনি যদি এমন একটি সিঙ্ক অ্যাডাপ্টার ডিজাইন করেন যা সার্ভার থেকে পরিচিতি সরবরাহকারীতে র কন্ট্যাক্ট ডেটা যোগ করবে এবং আপনি গ্রুপ ব্যবহার না করেন, তাহলে আপনার ডেটা দৃশ্যমান করার জন্য আপনাকে সরবরাহকারীকে বলতে হবে। ব্যবহারকারী ডিভাইসে অ্যাকাউন্ট যোগ করার সময় যে কোডটি এক্সিকিউট করা হয়, সেটিতে ContactsContract.Settings সারিটি আপডেট করুন যা পরিচিতি সরবরাহকারী অ্যাকাউন্টের জন্য যোগ করে। এই সারিতে, Settings.UNGROUPED_VISIBLE কলামের ভ্যালু ১ হিসেবে সেট করুন। আপনি এটি করলে, পরিচিতি সরবরাহকারী সবসময় আপনার পরিচিতির ডেটা দেখাবে, এমনকি আপনি গ্রুপ ব্যবহার না করলেও।

পরিচিতির ফটো

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-এর রেফারেন্স ডকুমেন্টেশনে ফটো সংক্রান্ত তথ্য ফিরিয়ে আনার উদাহরণ রয়েছে। র কন্ট্যাক্টের জন্য প্রাইমারি থাম্বনেল ফিরিয়ে আনার কোনও কনভেনিয়েন্স ক্লাস নেই, তবে আপনি র কন্ট্যাক্টের প্রাইমারি ফটো রো খুঁজে পেতে, র কন্ট্যাক্টের _ID, Photo.CONTENT_ITEM_TYPE এবং IS_PRIMARY কলাম বেছে নিয়ে ContactsContract.Data টেবিলে কোয়েরি পাঠাতে পারেন।

কোনও ব্যক্তির সোশ্যাল স্ট্রিম ডেটাতে ফটোও অন্তর্ভুক্ত থাকতে পারে। এগুলি android.provider.ContactsContract.StreamItemPhotos টেবিলে স্টোর করা হয়, যা সোশ্যাল স্ট্রিম ফটো বিভাগে আরও বিস্তারিতভাবে বর্ণনা করা হয়েছে।