কন্টেন্ট প্রোভাইডার ডেটার সেন্ট্রাল রিপোজিটরিতে অ্যাক্সেস ম্যানেজ করে। আপনি Android অ্যাপ্লিকেশনে এক বা একাধিক ক্লাস হিসেবে
প্রোভাইডার প্রয়োগ করেন, এর সাথে ম্যানিফেস্ট ফাইলে
এলিমেন্টও থাকে। আপনার একটি ক্লাস ContentProvider-এর সাবক্লাস প্রয়োগ করে, যা আপনার পরিষেবা প্রদানকারী ও অন্যান্য অ্যাপ্লিকেশনের
মধ্যে ইন্টারফেস হিসেবে কাজ করে।
যদিও কন্টেন্ট প্রোভাইডার অন্যান্য অ্যাপ্লিকেশনের জন্য ডেটা উপলভ্য করার জন্য তৈরি করা হয়েছে, আপনার অ্যাপ্লিকেশনে এমন অ্যাক্টিভিটি থাকতে পারে যা ব্যবহারকারীকে আপনার প্রোভাইডার দ্বারা ম্যানেজ করা ডেটা কোয়েরি এবং পরিবর্তন করতে দেয়।
এই পৃষ্ঠায় কন্টেন্ট প্রোভাইডার তৈরি করার প্রাথমিক প্রসেস এবং ব্যবহার করার জন্য API-এর তালিকা আছে।
তৈরি করা শুরু করার আগে
প্রোভাইডার তৈরি করা শুরু করার আগে, নিম্নলিখিত বিষয়গুলি বিবেচনা করুন:
-
আপনার কন্টেন্ট প্রোভাইডার প্রয়োজন কিনা তা ঠিক করুন। আপনি নিম্নলিখিত এক বা একাধিক ফিচার প্রদান করতে চাইলে,
আপনাকে কন্টেন্ট প্রোভাইডার তৈরি করতে হবে:
- আপনি অন্যান্য অ্যাপ্লিকেশনে জটিল ডেটা বা ফাইল অফার করতে চান।
- আপনি চান যে ব্যবহারকারীরা আপনার অ্যাপ থেকে জটিল ডেটা কপি করে অন্য অ্যাপে পেস্ট করুক।
- আপনি সার্চ ফ্রেমওয়ার্ক ব্যবহার করে কাস্টম সার্চ সাজেশন দিতে চান।
- আপনি উইজেটে আপনার অ্যাপ্লিকেশন ডেটা দেখাতে চান।
- আপনি
AbstractThreadedSyncAdapter,CursorAdapter, অথবাCursorLoaderক্লাস প্রয়োগ করতে চান।
আপনার নিজস্ব অ্যাপ্লিকেশনের মধ্যে সম্পূর্ণভাবে ব্যবহার করা হলে এবং উপরে তালিকাভুক্ত কোনও ফিচারের প্রয়োজন না হলে, ডেটাবেস বা অন্যান্য ধরনের পারসিস্টেন্ট স্টোরেজ ব্যবহার করার জন্য আপনার কোনও পরিষেবা প্রদানকারীর প্রয়োজন নেই। পরিবর্তে, আপনি ডেটা ও ফাইল স্টোরেজ ওভারভিউ-এ বর্ণিত স্টোরেজ সিস্টেমগুলির মধ্যে একটি ব্যবহার করতে পারেন।
- আপনি আগে থেকে এটি না করে থাকলে, কন্টেন্ট প্রোভাইডারের প্রাথমিক তথ্য পড়ুন যাতে প্রোভাইডার এবং তারা কীভাবে কাজ করে সেই সম্পর্কে আরও জানতে পারেন।
এর পরে, আপনার পরিষেবা প্রদানকারী তৈরি করতে এইসব ধাপ অনুসরণ করুন:
-
আপনার ডেটার জন্য র স্টোরেজ ডিজাইন করুন। কন্টেন্ট প্রোভাইডার দু'টি উপায়ে ডেটা প্রদান করে:
- ফাইল ডেটা
- সাধারণত ফাইলে থাকে এমন ডেটা, যেমন ফটো, অডিও বা ভিডিও। আপনার অ্যাপ্লিকেশনের প্রাইভেট স্পেসে ফাইলগুলি স্টোর করুন। অন্য অ্যাপ্লিকেশন থেকে ফাইলের জন্য অনুরোধের উত্তরে, আপনার পরিষেবা প্রদানকারী ফাইলের জন্য একটি হ্যান্ডেল অফার করতে পারে।
- "স্ট্রাকচার্ড" ডেটা
- ডেটা যা সাধারণত ডেটাবেস, অ্যারে বা একই ধরনের স্ট্রাকচারে যায়। সারি ও কলামের টেবিলের সাথে মানানসই ফর্ম্যাটে ডেটা স্টোর করুন। একটি সারি একটি এন্টিটি উপস্থাপন করে, যেমন কোনও ব্যক্তি বা ইনভেনটরিতে থাকা কোনও আইটেম। একটি কলাম এন্টিটির জন্য কিছু ডেটা দেখায়, যেমন কোনও ব্যক্তির নাম বা কোনও আইটেমের দাম। এই ধরনের ডেটা স্টোর করার সাধারণ উপায় হল SQLite ডেটাবেস, তবে আপনি যেকোনও ধরনের পারসিস্টেন্ট স্টোরেজ ব্যবহার করতে পারেন। Android সিস্টেমে উপলভ্য স্টোরেজের ধরন সম্পর্কে আরও জানতে, ডেটা স্টোরেজ ডিজাইন করুন বিভাগ দেখুন।
-
ContentProviderক্লাস এবং এর প্রয়োজনীয় পদ্ধতির একটি কংক্রিট ইমপ্লিমেন্টেশন নির্ধারণ করুন। এই ক্লাসটি আপনার ডেটা এবং Android সিস্টেমের বাকি অংশের মধ্যে ইন্টারফেস হিসেবে কাজ করে। এই ক্লাস সম্পর্কে আরও তথ্যের জন্য, ContentProvider ক্লাস প্রয়োগ করুন বিভাগ দেখুন। - প্রদানকারীর অথরিটি স্ট্রিং, কন্টেন্ট URI এবং কলামের নাম নির্ধারণ করুন। আপনি যদি চান যে প্রোভাইডারের অ্যাপ্লিকেশন ইনটেন্ট ম্যানেজ করুক, তাহলে ইনটেন্ট অ্যাকশন, অতিরিক্ত ডেটা এবং ফ্ল্যাগও নির্ধারণ করুন। এছাড়াও, আপনার ডেটা অ্যাক্সেস করতে চায় এমন অ্যাপ্লিকেশনের জন্য আপনার প্রয়োজনীয় অনুমতি সংজ্ঞায়িত করুন। এইসব ভ্যালুকে একটি আলাদা কনট্র্যাক্ট ক্লাসে ধ্রুবক হিসেবে সংজ্ঞায়িত করার কথা বিবেচনা করুন। পরে, আপনি এই ক্লাস অন্যান্য ডেভেলপারদের দেখাতে পারবেন। কন্টেন্ট URI সম্পর্কে আরও জানতে, কন্টেন্ট URI ডিজাইন করুন বিভাগ দেখুন। ইনটেন্ট সম্পর্কে আরও তথ্যের জন্য, ইনটেন্ট ও ডেটা অ্যাক্সেস বিভাগ দেখুন।
-
অন্যান্য ঐচ্ছিক অংশ যোগ করুন, যেমন স্যাম্পেল ডেটা বা
AbstractThreadedSyncAdapter-এর ইমপ্লিমেন্টেশন যা প্রোভাইডার ও ক্লাউড-ভিত্তিক ডেটার মধ্যে ডেটা সিঙ্ক করতে পারে।
ডিজাইন ডেটা স্টোরেজ
কন্টেন্ট প্রোভাইডার হল স্ট্রাকচার্ড ফর্ম্যাটে সেভ করা ডেটার ইন্টারফেস। ইন্টারফেস তৈরি করার আগে, ডেটা কীভাবে স্টোর করবেন তা ঠিক করুন। আপনি নিজের পছন্দমতো যেকোনও ফর্মে ডেটা স্টোর করতে পারেন এবং তারপরে প্রয়োজন অনুযায়ী ডেটা রিড ও রাইট করার জন্য ইন্টারফেস ডিজাইন করতে পারেন।
Android-এ উপলভ্য কিছু ডেটা স্টোরেজ টেকনোলজি এখানে উল্লেখ করা হল:
- আপনি যদি স্ট্রাকচার্ড ডেটা নিয়ে কাজ করেন, তাহলে SQLite-এর মতো রিলেশনাল ডেটাবেস অথবা LevelDB-এর মতো নন-রিলেশনাল কী-ভ্যালু ডেটাস্টোর ব্যবহার করার কথা বিবেচনা করুন। আপনি যদি অডিও, ছবি বা ভিডিও মিডিয়ার মতো আনস্ট্রাকচার্ড ডেটা নিয়ে কাজ করেন, তাহলে ডেটা ফাইল হিসেবে সেভ করার কথা বিবেচনা করুন। আপনি বিভিন্ন ধরনের স্টোরেজ মিশিয়ে ও মিলিয়ে দেখতে পারেন এবং প্রয়োজন হলে একটি কন্টেন্ট প্রোভাইডার ব্যবহার করে সেগুলি দেখাতে পারেন।
-
Android সিস্টেম রুম পারসিসটেন্স লাইব্রেরির সাথে ইন্টার্যাক্ট করতে পারে, যা
SQLite ডেটাবেস API-তে অ্যাক্সেস প্রদান করে, যা Android-এর নিজস্ব প্রোভাইডাররা
টেবিল-ভিত্তিক ডেটা স্টোর করতে ব্যবহার করে। এই লাইব্রেরি ব্যবহার করে ডেটাবেস তৈরি করতে,
RoomDatabase-এর সাবক্লাস ইনস্ট্যান্টিয়েট করুন, যেমন রুম ব্যবহার করে লোকাল ডেটাবেসে ডেটা সেভ করুন-এ বর্ণনা করা হয়েছে।আপনার রিপোজিটরি প্রয়োগ করার জন্য আপনাকে ডেটাবেস ব্যবহার করতে হবে না। একটি প্রোভাইডার বাহ্যিকভাবে টেবিলের একটি সেট হিসাবে উপস্থিত হয়, যা একটি রিলেশনাল ডেটাবেসের মতো, তবে এটি প্রোভাইডারের অভ্যন্তরীণ বাস্তবায়নের জন্য প্রয়োজনীয় নয়।
- ফাইলের ডেটা স্টোর করার জন্য, Android-এ বিভিন্ন ধরনের ফাইল-ওরিয়েন্টেড API আছে। ফাইল স্টোরেজ সম্পর্কে আরও জানতে, ডেটা ও ফাইল স্টোরেজ ওভারভিউ পড়ুন। আপনি যদি এমন কোনও প্রোভাইডার ডিজাইন করেন যা মিউজিক বা ভিডিওর মতো মিডিয়া-সম্পর্কিত ডেটা অফার করে, তাহলে আপনার কাছে এমন একটি প্রোভাইডার থাকতে পারে যা টেবিল ডেটা এবং ফাইলগুলিকে একত্রিত করে।
- বিরল কিছু ক্ষেত্রে, একটি অ্যাপ্লিকেশনের জন্য একাধিক কন্টেন্ট প্রোভাইডার প্রয়োগ করলে আপনি উপকৃত হতে পারেন। যেমন, আপনি হয়ত একটি কন্টেন্ট প্রোভাইডার ব্যবহার করে কোনও উইজেটের সাথে কিছু ডেটা শেয়ার করতে চান এবং অন্যান্য অ্যাপ্লিকেশনের সাথে শেয়ার করার জন্য অন্য একটি ডেটা সেট প্রকাশ করতে চান।
-
নেটওয়ার্ক-ভিত্তিক ডেটা নিয়ে কাজ করার জন্য,
java.netএবংandroid.net-এ ক্লাস ব্যবহার করুন। এছাড়াও, আপনি নেটওয়ার্ক-ভিত্তিক ডেটা স্থানীয় ডেটা স্টোরে সিঙ্ক করতে পারেন, যেমন ডেটাবেস এবং তারপর ডেটা টেবিল বা ফাইল হিসেবে অফার করতে পারেন।
মনে রাখবেন: আপনি যদি নিজের রিপোজিটরিতে এমন কোনও পরিবর্তন করেন যা ব্যাকওয়ার্ড কম্প্যাটিবল নয়, তাহলে আপনাকে রিপোজিটরিটিকে একটি নতুন ভার্সন নম্বর দিয়ে চিহ্নিত করতে হবে। এছাড়াও, নতুন কন্টেন্ট প্রোভাইডার প্রয়োগ করে এমন অ্যাপের ভার্সন নম্বর আপনাকে বাড়াতে হবে। এই পরিবর্তন করলে, সিস্টেম ডাউনগ্রেড করার সময় এমন কোনও অ্যাপ আবার ইনস্টল করার চেষ্টা করলে সিস্টেম ক্র্যাশ করে না, যে অ্যাপের কন্টেন্ট প্রোভাইডার সিস্টেমের সাথে মানানসই নয়।
ডেটা ডিজাইন সংক্রান্ত বিবেচনা
আপনার পরিষেবা প্রদানকারীর ডেটা স্ট্রাকচার ডিজাইন করার জন্য এখানে কিছু পরামর্শ দেওয়া হল:
-
টেবিল ডেটাতে সবসময় "প্রাথমিক কী" কলাম থাকতে হবে যা পরিষেবা প্রদানকারী প্রতিটি সারির জন্য
অনন্য সংখ্যাসূচক মান হিসেবে বজায় রাখে। আপনি এই ভ্যালু ব্যবহার করে অন্য সারণীর সম্পর্কিত সারির সাথে
সারি লিঙ্ক করতে পারবেন ("ফরেন কী" হিসেবে এটি ব্যবহার করে)। যদিও আপনি এই কলামের জন্য যেকোনও নাম ব্যবহার করতে পারেন,
তবে
BaseColumns._IDব্যবহার করা সবচেয়ে ভালো বিকল্প, কারণ কোনও প্রোভাইডার কোয়েরির ফলাফলকেListView-এর সাথে লিঙ্ক করতে হলে, উদ্ধার করা কলামগুলির মধ্যে একটির নাম_IDহতে হবে। -
আপনি যদি বিটম্যাপ ছবি বা ফাইল-ভিত্তিক ডেটার অন্যান্য খুব বড় অংশ প্রদান করতে চান, তাহলে ডেটা একটি ফাইলে স্টোর করুন
এবং তারপরে এটি সরাসরি টেবিলে স্টোর করার পরিবর্তে পরোক্ষভাবে প্রদান করুন। আপনি এটি করলে, আপনার পরিষেবা প্রদানকারীর ব্যবহারকারীদের জানাতে হবে যে ডেটা অ্যাক্সেস করার জন্য তাদের
ContentResolverফাইল পদ্ধতি ব্যবহার করতে হবে। -
বাইনারি লার্জ অবজেক্ট (BLOB) ডেটার ধরন ব্যবহার করে এমন ডেটা স্টোর করুন যার সাইজ বা স্ট্রাকচার
পরিবর্তনশীল। যেমন, আপনি BLOB কলাম ব্যবহার করে
প্রোটোকল বাফার বা
JSON স্ট্রাকচার সেভ করতে পারেন।
এছাড়াও, আপনি স্কিমা-ইন্ডিপেন্ডেন্ট টেবিল প্রয়োগ করতে BLOB ব্যবহার করতে পারেন। এই ধরনের টেবিলে, আপনি একটি প্রাথমিক কী কলাম, একটি MIME প্রকার কলাম এবং এক বা একাধিক জেনেরিক কলাম BLOB হিসেবে সংজ্ঞায়িত করেন। BLOB কলামে ডেটার অর্থ MIME প্রকার কলামের মান দ্বারা নির্দেশিত হয়। এটি আপনাকে একই টেবিলে বিভিন্ন ধরনের সারি স্টোর করতে দেয়। পরিচিতি সরবরাহকারীর "ডেটা" টেবিল
ContactsContract.Dataহল স্কিমা-ইন্ডিপেন্ডেন্ট টেবিলের উদাহরণ।
কন্টেন্ট URI ডিজাইন করুন
কন্টেন্ট URI হল এমন একটি URI যা কোনও প্রোভাইডারের ডেটা শনাক্ত করে। কন্টেন্ট URI-তে
পুরো প্রোভাইডারের প্রতীকী নাম (এর কর্তৃত্ব) এবং
টেবিল বা ফাইলকে নির্দেশ করে এমন নাম (একটি পাথ) অন্তর্ভুক্ত থাকে। ঐচ্ছিক আইডি অংশটি
টেবিলের একটি স্বতন্ত্র সারিকে নির্দেশ করে। ContentProvider-এর প্রতিটি ডেটা অ্যাক্সেস পদ্ধতিতে
আর্গুমেন্ট হিসেবে কন্টেন্ট URI থাকে। এটি আপনাকে
অ্যাক্সেস করার জন্য টেবিল, সারি বা ফাইল নির্ধারণ করতে দেয়।
কন্টেন্ট URI সম্পর্কে তথ্যের জন্য, কন্টেন্ট প্রোভাইডার সম্পর্কিত প্রাথমিক তথ্য দেখুন।
কর্তৃপক্ষ ডিজাইন করুন
সাধারণত কোনও প্রদানকারীর একটিই অথরিটি থাকে, যা তার Android-ইন্টার্নাল নাম হিসেবে কাজ করে। অন্যান্য প্রদানকারীর সাথে বিরোধ এড়াতে, আপনার প্রদানকারী কর্তৃপক্ষের ভিত্তি হিসেবে ইন্টারনেট ডোমেন মালিকানা (বিপরীত ক্রমে) ব্যবহার করুন। এই সাজেশন Android প্যাকেজের নামের ক্ষেত্রেও প্রযোজ্য, তাই আপনি প্রোভাইডার অথরিটিকে প্রোভাইডার সহ প্যাকেজের নামের এক্সটেনশন হিসেবে সংজ্ঞায়িত করতে পারেন।
যেমন, আপনার Android প্যাকেজের নাম
com.example.<appname> হলে, আপনার পরিষেবা প্রদানকারীকে
com.example.<appname>.provider অথরিটি দিন।
পাথ স্ট্রাকচার ডিজাইন করো
ডেভেলপাররা সাধারণত অথরিটি থেকে কন্টেন্ট URI তৈরি করেন, এর জন্য তারা এমন পাথ যোগ করেন যা
নির্দিষ্ট টেবিলকে নির্দেশ করে। যেমন, আপনার কাছে দুটি টেবিল থাকলে, table1 এবং
table2, আপনি আগের উদাহরণের অথরিটি ব্যবহার করে সেগুলিকে একত্রিত করে
কন্টেন্ট URI
com.example.<appname>.provider/table1 এবং
com.example.<appname>.provider/table2 তৈরি করতে পারেন। পাথ একটিমাত্র সেগমেন্টের মধ্যে
সীমাবদ্ধ নয় এবং পাথের প্রতিটি লেভেলের জন্য টেবিল থাকার প্রয়োজন নেই।
কন্টেন্ট URI আইডি ম্যানেজ করুন
প্রথাগতভাবে, প্রদানকারীরা কন্টেন্ট URI গ্রহণ করে টেবিলের একটি সারিতে অ্যাক্সেস অফার করে
যেখানে URI-এর শেষে সারির জন্য একটি আইডি ভ্যালু থাকে। এছাড়াও, প্রথাগতভাবে, প্রদানকারীরা টেবিলের _ID কলামের সাথে
আইডি ভ্যালু ম্যাচ করে এবং যে সারিটি ম্যাচ করে তার জন্য
অনুরোধ করা অ্যাক্সেস প্রদান করে।
এই কনভেনশন কোনও পরিষেবা প্রদানকারীকে অ্যাক্সেস করা অ্যাপের জন্য একটি সাধারণ ডিজাইন প্যাটার্নকে সহজ করে তোলে। অ্যাপটি
প্রোভাইডারের কাছে কোয়েরি করে এবং CursorAdapter ব্যবহার করে ListView-এ
ফলাফল হিসেবে পাওয়া Cursor
দেখায়।
CursorAdapter-এর সংজ্ঞার জন্য Cursor-এর একটি কলামকে _ID হতে হবে
ব্যবহারকারী তারপর ডেটা দেখতে বা পরিবর্তন করতে UI থেকে দেখানো সারিগুলির মধ্যে একটি বেছে নেন। অ্যাপটি Cursor থেকে সংশ্লিষ্ট সারিটি পায় যা
ListView-কে ব্যাক আপ করে, এই সারির জন্য _ID ভ্যালু পায়, এটি কন্টেন্ট URI-তে যোগ করে
এবং পরিষেবা প্রদানকারীকে অ্যাক্সেসের অনুরোধ পাঠায়। তারপর, ব্যবহারকারীর বেছে নেওয়া নির্দিষ্ট সারির উপর ভিত্তি করে
প্রোভাইডার কোয়েরি বা পরিবর্তন করতে পারবেন।
কন্টেন্ট URI প্যাটার্ন
ইনকামিং কন্টেন্ট URI-এর জন্য কোন অ্যাকশন নিতে হবে তা বেছে নিতে আপনাকে সাহায্য করার জন্য, প্রোভাইডার API-তে
সুবিধাজনক ক্লাস UriMatcher অন্তর্ভুক্ত থাকে, যা কন্টেন্ট URI প্যাটার্নকে
ইন্টিজার ভ্যালুতে ম্যাপ করে। আপনি switch স্টেটমেন্টে পূর্ণসংখ্যা ব্যবহার করতে পারেন যা
কন্টেন্ট URI বা নির্দিষ্ট প্যাটার্নের সাথে মেলে এমন URI-এর জন্য কাঙ্ক্ষিত অ্যাকশন বেছে নেয়।
কন্টেন্ট URI প্যাটার্ন ওয়াইল্ডকার্ড অক্ষর ব্যবহার করে কন্টেন্ট URI-এর সাথে মেলে:
-
*যেকোনও দৈর্ঘ্যের যেকোনও সঠিক অক্ষরের স্ট্রিংয়ের সাথে ম্যাচ করে। -
#যেকোনও দৈর্ঘ্যের সংখ্যাসূচক অক্ষরের স্ট্রিংয়ের সাথে মেলে।
কন্টেন্ট URI হ্যান্ডলিং ডিজাইন ও কোডিং করার উদাহরণ হিসেবে, com.example.app.provider
কর্তৃত্ব সহ এমন একটি প্রোভাইডারের কথা বিবেচনা করুন যা সারণীর দিকে নির্দেশ করা
নিম্নলিখিত কন্টেন্ট URI শনাক্ত করে:
-
content://com.example.app.provider/table1:table1নামের টেবিল। -
content://com.example.app.provider/table2/dataset1:dataset1নামের একটি টেবিল। -
content://com.example.app.provider/table2/dataset2:dataset2নামের একটি টেবিল। -
content://com.example.app.provider/table3:table3নামের টেবিল।
প্রোভাইডার এই কন্টেন্ট URI-গুলিকেও শনাক্ত করে যদি সেগুলিতে একটি সারি আইডি যোগ করা থাকে, যেমন content://com.example.app.provider/table3/1-এর জন্য সারি শনাক্ত করা হয়
1-এর মাধ্যমে table3-এ।
নিম্নলিখিত কন্টেন্ট URI প্যাটার্নগুলি সম্ভব:
-
content://com.example.app.provider/* - প্রদানকারীর যেকোনও কন্টেন্ট URI-এর সাথে ম্যাচ করে।
-
content://com.example.app.provider/table2/* -
dataset1এবংdataset2টেবিলের জন্য কন্টেন্ট URI-এর সাথে ম্যাচ করে, কিন্তুtable1বাtable3-এর জন্য কন্টেন্ট URI-এর সাথে ম্যাচ করে না। -
content://com.example.app.provider/table3/# -
table3-এ একক সারির জন্য কন্টেন্ট URI-এর সাথে ম্যাচ করে, যেমন6দ্বারা শনাক্ত করা সারির জন্যcontent://com.example.app.provider/table3/6।
UriMatcher-এ পদ্ধতিগুলি কীভাবে কাজ করে তা নিম্নলিখিত কোড স্নিপেট থেকে জানতে পারবেন।
এই কোডটি টেবিলের জন্য কন্টেন্ট URI প্যাটার্ন
content://<authority>/<path> এবং
একক সারির জন্য content://<authority>/<path>/<id> ব্যবহার করে
একক সারির URI থেকে আলাদাভাবে সম্পূর্ণ টেবিলের URI ম্যানেজ করে।
addURI() পদ্ধতিটি একটি
অথরিটি এবং পাথকে একটি পূর্ণসংখ্যা মানের সাথে ম্যাপ করে। match() পদ্ধতিটি URI-এর জন্য পূর্ণসংখ্যা মান প্রদান করে। একটি switch স্টেটমেন্ট
সম্পূর্ণ টেবিল কোয়েরি করা এবং একটি রেকর্ডের জন্য কোয়েরি করার মধ্যে বেছে নেয়।
Kotlin
private val sUriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply { /* * The calls to addURI() go here for all the content URI patterns that the provider * recognizes. For this snippet, only the calls for table 3 are shown. */ /* * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used * in the path. */ addURI("com.example.app.provider", "table3", 1) /* * Sets the code for a single row to 2. In this case, the # wildcard is * used. content://com.example.app.provider/table3/3 matches, but * content://com.example.app.provider/table3 doesn't. */ addURI("com.example.app.provider", "table3/#", 2) } ... class ExampleProvider : ContentProvider() { ... // Implements ContentProvider.query() override fun query( uri: Uri?, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String? ): Cursor? { var localSortOrder: String = sortOrder ?: "" var localSelection: String = selection ?: "" when (sUriMatcher.match(uri)) { 1 -> { // If the incoming URI was for all of table3 if (localSortOrder.isEmpty()) { localSortOrder = "_ID ASC" } } 2 -> { // If the incoming URI was for a single row /* * Because this URI was for a single row, the _ID value part is * present. Get the last path segment from the URI; this is the _ID value. * Then, append the value to the WHERE clause for the query. */ localSelection += "_ID ${uri?.lastPathSegment}" } else -> { // If the URI isn't recognized, // do some error handling here } } // Call the code to actually do the query } }
জাভা
public class ExampleProvider extends ContentProvider { ... // Creates a UriMatcher object. private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); static { /* * The calls to addURI() go here for all the content URI patterns that the provider * recognizes. For this snippet, only the calls for table 3 are shown. */ /* * Sets the integer value for multiple rows in table 3 to one. No wildcard is used * in the path. */ uriMatcher.addURI("com.example.app.provider", "table3", 1); /* * Sets the code for a single row to 2. In this case, the # wildcard is * used. content://com.example.app.provider/table3/3 matches, but * content://com.example.app.provider/table3 doesn't. */ uriMatcher.addURI("com.example.app.provider", "table3/#", 2); } ... // Implements ContentProvider.query() public Cursor query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { ... /* * Choose the table to query and a sort order based on the code returned for the incoming * URI. Here, too, only the statements for table 3 are shown. */ switch (uriMatcher.match(uri)) { // If the incoming URI was for all of table3 case 1: if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC"; break; // If the incoming URI was for a single row case 2: /* * Because this URI was for a single row, the _ID value part is * present. Get the last path segment from the URI; this is the _ID value. * Then, append the value to the WHERE clause for the query. */ selection = selection + "_ID = " + uri.getLastPathSegment(); break; default: ... // If the URI isn't recognized, do some error handling here } // Call the code to actually do the query }
অন্য ক্লাস, ContentUris, কন্টেন্ট URI-এর id অংশের সাথে কাজ করার জন্য
সুবিধাজনক পদ্ধতি প্রদান করে। Uri এবং
Uri.Builder ক্লাসে আগে থেকে থাকা Uri অবজেক্ট পার্স করা এবং নতুন অবজেক্ট তৈরি করার জন্য সুবিধাজনক পদ্ধতি অন্তর্ভুক্ত রয়েছে।
ContentProvider ক্লাস প্রয়োগ করা
ContentProvider ইনস্ট্যান্স অন্যান্য অ্যাপ্লিকেশন থেকে অনুরোধ ম্যানেজ করার মাধ্যমে
ডেটার স্ট্রাকচার্ড সেটে অ্যাক্সেস ম্যানেজ করে। অ্যাক্সেসের সব ফর্ম
অবশেষে ContentResolver কল করে, যা পরে অ্যাক্সেস পেতে
ContentProvider-এর একটি কনক্রিট পদ্ধতি কল করে।
প্রয়োজনীয় পদ্ধতি
অ্যাবস্ট্রাক্ট ক্লাস ContentProvider ছয়টি অ্যাবস্ট্রাক্ট পদ্ধতি নির্ধারণ করে যা
আপনি নিজের কনক্রিট সাবক্লাসের অংশ হিসেবে প্রয়োগ করেন। onCreate() ছাড়া এইসব পদ্ধতি
ক্লায়েন্ট অ্যাপ্লিকেশন দ্বারা কল করা হয়
যা আপনার কন্টেন্ট প্রোভাইডার অ্যাক্সেস করার চেষ্টা করছে।
-
query() -
আপনার পরিষেবা প্রদানকারীর থেকে ডেটা ফিরিয়ে আনা। কোয়েরি করার জন্য টেবিল, দেখানোর জন্য সারি ও কলাম এবং ফলাফলের ক্রমানুসারে সাজানোর সেটিং বেছে নিতে
আর্গুমেন্ট ব্যবহার করুন।
Cursorঅবজেক্ট হিসেবে ডেটা দেখায়। -
insert() - আপনার প্রোভাইডারে নতুন সারি যোগ করুন। ডেস্টিনেশন টেবিল বেছে নিতে এবং ব্যবহার করার জন্য কলামের ভ্যালু পেতে আর্গুমেন্ট ব্যবহার করুন। নতুন যোগ করা সারির জন্য কন্টেন্ট URI রিটার্ন করুন।
-
update() - আপনার পরিষেবা প্রদানকারীর মধ্যে আগে থেকে থাকা সারি আপডেট করুন। আপডেট করার জন্য এবং আপডেট করা কলামের ভ্যালু পাওয়ার জন্য টেবিল এবং সারি বেছে নিতে আর্গুমেন্ট ব্যবহার করুন। আপডেট করা সারির সংখ্যা দেখায়।
-
delete() - আপনার পরিষেবা প্রদানকারীর থেকে সারি মুছুন। টেবিল এবং মুছে ফেলার জন্য সারিগুলি নির্বাচন করতে আর্গুমেন্ট ব্যবহার করুন। মুছে ফেলা সারির সংখ্যা দেখায়।
-
getType() - কন্টেন্ট URI-এর সাথে সম্পর্কিত MIME-এর ধরন ফিরিয়ে দিন। এই পদ্ধতিটি কন্টেন্ট প্রোভাইডার MIME-এর প্রকার প্রয়োগ করুন বিভাগে আরও বিস্তারিতভাবে বর্ণনা করা হয়েছে।
-
onCreate() -
আপনার পরিষেবা প্রদানকারীকে ইনিশিয়ালাইজ করুন। Android সিস্টেম আপনার প্রোভাইডার তৈরি করার সাথে সাথেই
এই পদ্ধতিকে কল করে। আপনার প্রদানকারী তৈরি করা হয় না যতক্ষণ না একটি
ContentResolverঅবজেক্ট এটি অ্যাক্সেস করার চেষ্টা করে।
এইসব পদ্ধতিতে একই নামের ContentResolver পদ্ধতির মতো একই সিগনেচার
রয়েছে।
এইসব পদ্ধতি প্রয়োগ করার সময় আপনাকে নিম্নলিখিত বিষয়গুলি বিবেচনা করতে হবে:
-
onCreate()ছাড়া এইসব পদ্ধতি একাধিক থ্রেড একবারে কল করতে পারে, তাই এগুলি থ্রেড-সেফ হতে হবে। একাধিক থ্রেড সম্পর্কে আরও জানতে, প্রসেস ও থ্রেডের ওভারভিউ দেখুন। -
onCreate()-এ দীর্ঘ অপারেশন করা এড়িয়ে চলুন। প্রয়োজন না হওয়া পর্যন্ত ইনিশিয়ালাইজেশন টাস্ক স্থগিত রাখুন। onCreate() পদ্ধতি প্রয়োগ করা সংক্রান্ত বিভাগে এই বিষয়ে আরও বিস্তারিত আলোচনা করা হয়েছে। -
আপনাকে এইসব পদ্ধতি প্রয়োগ করতে হলেও, আপনার কোডকে প্রত্যাশিত ডেটার ধরন রিটার্ন করা ছাড়া
আর কিছু করতে হবে না। যেমন, আপনি
insert()-এ কল উপেক্ষা করে এবং 0 রিটার্ন করে অন্যান্য অ্যাপ্লিকেশনকে কিছু টেবিলে ডেটা যোগ করা থেকে আটকাতে পারেন।
query() পদ্ধতি প্রয়োগ করা
ContentProvider.query()
পদ্ধতিকে অবশ্যই একটি Cursor অবজেক্ট রিটার্ন করতে হবে অথবা, এটি
ব্যর্থ হলে, একটি Exception থ্রো করতে হবে। আপনি ডেটা স্টোরেজ হিসেবে SQLite ডেটাবেস ব্যবহার করলে, SQLiteDatabase ক্লাসের query() পদ্ধতির মধ্যে কোনও একটির মাধ্যমে
ফেরত পাওয়া Cursor আপনি ফেরত দিতে পারবেন।
কোয়েরি কোনও সারির সাথে ম্যাচ না করলে, এমন একটি Cursor
ইনস্ট্যান্স রিটার্ন করুন যার getCount() পদ্ধতি ০ রিটার্ন করে।
কোয়েরি প্রসেস করার সময় কোনও ইন্টার্নাল সমস্যা হলে তবেই null রিটার্ন করুন।
আপনার ডেটা স্টোরেজ হিসেবে SQLite ডেটাবেস ব্যবহার না করলে, Cursor-এর কোনও একটি কনক্রিট সাবক্লাস
ব্যবহার করুন। যেমন, MatrixCursor ক্লাস
এমন একটি কার্সর প্রয়োগ করে যেখানে প্রতিটি সারি হল Object ইনস্ট্যান্সের একটি অ্যারে। এই ক্লাসের সাথে,
নতুন সারি যোগ করতে addRow() ব্যবহার করুন।
Android সিস্টেমকে অবশ্যই প্রসেস বাউন্ডারি জুড়ে Exception
কমিউনিকেট করতে সক্ষম হতে হবে। Android নিম্নলিখিত ব্যতিক্রমগুলির জন্য এটি করতে পারে যা কোয়েরি সংক্রান্ত সমস্যা
সমাধান করার ক্ষেত্রে উপযোগী:
-
IllegalArgumentException। আপনার পরিষেবা প্রদানকারী কোনও ভুল কন্টেন্ট URI পেলে, আপনি এটি থ্রো করার বিকল্প বেছে নিতে পারেন। -
NullPointerException
insert() পদ্ধতি প্রয়োগ করুন
insert() পদ্ধতি ContentValues আর্গুমেন্টের
ভ্যালু ব্যবহার করে উপযুক্ত টেবিলে
নতুন সারি যোগ করে। ContentValues আর্গুমেন্টে কলামের নাম না থাকলে, আপনি হয়ত আপনার প্রদানকারী কোড বা ডেটাবেস স্কিমাতে
এর জন্য ডিফল্ট ভ্যালু দিতে চাইবেন।
এই পদ্ধতি নতুন সারির জন্য কন্টেন্ট URI রিটার্ন করে। এটি তৈরি করতে, withAppendedId() ব্যবহার করে, টেবিলের কন্টেন্ট URI-তে নতুন সারির প্রাথমিক কী, সাধারণত _ID ভ্যালু, যোগ করুন।
delete() পদ্ধতি প্রয়োগ করুন
delete() পদ্ধতিকে
আপনার ডেটা স্টোরেজ থেকে সারি মুছতে হবে না। আপনি যদি আপনার পরিষেবা প্রদানকারীর সাথে
সিঙ্ক অ্যাডাপ্টার ব্যবহার করেন, তাহলে সম্পূর্ণ রোটি সরানোর পরিবর্তে "মুছুন" ফ্ল্যাগ সহ একটি মুছে ফেলা রো চিহ্নিত করার কথা বিবেচনা করুন। সিঙ্ক অ্যাডাপ্টার
মুছে ফেলা সারি চেক করতে এবং প্রদানকারীর থেকে মুছে ফেলার আগে সার্ভার থেকে সেগুলি সরাতে পারে।
update() পদ্ধতি প্রয়োগ করুন
update() পদ্ধতিটি ContentValues আর্গুমেন্ট ব্যবহার করে যা
insert()-এর দ্বারা ব্যবহৃত হয় এবং
একই selection এবং selectionArgs আর্গুমেন্ট ব্যবহার করে যা
delete() এবং
ContentProvider.query()-এর দ্বারা ব্যবহৃত হয়।
এটি আপনাকে এইসব পদ্ধতির মধ্যে কোড আবার ব্যবহার করার অনুমতি দিতে পারে।
onCreate() পদ্ধতি প্রয়োগ করুন
Android সিস্টেম onCreate() কল করে
যখন এটি প্রোভাইডার চালু করে। এই পদ্ধতিতে শুধুমাত্র দ্রুত-চলমান ইনিশিয়ালাইজেশন
টাস্ক পারফর্ম করুন এবং ডেটাবেস তৈরি ও ডেটা লোড করা স্থগিত রাখুন যতক্ষণ না প্রোভাইডার ডেটার জন্য
অনুরোধ পাচ্ছে। আপনি যদি onCreate()-এ
দীর্ঘ টাস্ক করেন, তাহলে আপনার
প্রোভাইডারের স্টার্টআপ স্লো হয়ে যায়। এর ফলে, পরিষেবা প্রদানকারী অন্যান্য অ্যাপ্লিকেশনে উত্তর দিতে
সময় নেয়।
নিম্নলিখিত দুটি স্নিপেট
ContentProvider.onCreate() এবং
Room.databaseBuilder()-এর মধ্যে ইন্টার্যাকশন দেখায়। প্রথম
স্নিপেট ContentProvider.onCreate()-এর প্রয়োগ দেখায়
যেখানে ডেটাবেস অবজেক্ট তৈরি করা হয় এবং
ডেটা অ্যাক্সেস অবজেক্টের হ্যান্ডেল তৈরি করা হয়:
Kotlin
// Defines the database name private const val DBNAME = "mydb" ... class ExampleProvider : ContentProvider() { // Defines a handle to the Room database private lateinit var appDatabase: AppDatabase // Defines a Data Access Object to perform the database operations private var userDao: UserDao? = null override fun onCreate(): Boolean { // Creates a new database object appDatabase = Room.databaseBuilder(context, AppDatabase::class.java, DBNAME).build() // Gets a Data Access Object to perform the database operations userDao = appDatabase.userDao return true } ... // Implements the provider's insert method override fun insert(uri: Uri, values: ContentValues?): Uri? { // Insert code here to determine which DAO to use when inserting data, handle error conditions, etc. } }
জাভা
public class ExampleProvider extends ContentProvider // Defines a handle to the Room database private AppDatabase appDatabase; // Defines a Data Access Object to perform the database operations private UserDao userDao; // Defines the database name private static final String DBNAME = "mydb"; public boolean onCreate() { // Creates a new database object appDatabase = Room.databaseBuilder(getContext(), AppDatabase.class, DBNAME).build(); // Gets a Data Access Object to perform the database operations userDao = appDatabase.getUserDao(); return true; } ... // Implements the provider's insert method public Cursor insert(Uri uri, ContentValues values) { // Insert code here to determine which DAO to use when inserting data, handle error conditions, etc. } }
ContentProvider MIME-এর ধরন প্রয়োগ করুন
MIME-এর ধরন ফিরিয়ে দেওয়ার জন্য ContentProvider ক্লাসের দুটি পদ্ধতি আছে:
-
getType() - কোনও পরিষেবা প্রদানকারীর জন্য আপনি যে প্রয়োজনীয় পদ্ধতি প্রয়োগ করেন তার মধ্যে একটি।
-
getStreamTypes() - আপনার পরিষেবা প্রদানকারী ফাইল অফার করলে, আপনাকে একটি পদ্ধতি প্রয়োগ করতে হবে।
টেবিলের জন্য MIME-এর ধরন
getType() পদ্ধতিটি MIME ফর্ম্যাটে একটি
String প্রদান করে যা কন্টেন্ট URI আর্গুমেন্ট দ্বারা প্রদান করা ডেটার ধরন বর্ণনা করে। Uri আর্গুমেন্টটি নির্দিষ্ট URI-এর পরিবর্তে একটি প্যাটার্ন হতে পারে।
এই ক্ষেত্রে, প্যাটার্নের সাথে মেলে এমন কন্টেন্ট URI-এর সাথে সম্পর্কিত ডেটার ধরন ফিরিয়ে দিন।
টেক্সট, HTML বা JPEG-এর মতো সাধারণ ধরনের ডেটার জন্য,
getType() সেই ডেটার জন্য স্ট্যান্ডার্ড
MIME-এর প্রকার রিটার্ন করে। এইসব স্ট্যান্ডার্ড ধরনের সম্পূর্ণ তালিকা
IANA MIME মিডিয়ার ধরন
ওয়েবসাইটে উপলভ্য।
টেবিল ডেটার সারি বা সারিগুলিকে পয়েন্ট করে এমন কন্টেন্ট URI-এর জন্য,
getType()
Android-এর ভেন্ডর-নির্দিষ্ট MIME ফর্ম্যাটে একটি MIME-এর প্রকার রিটার্ন করে:
-
অংশ টাইপ করুন:
vnd -
সাবটাইপ পার্ট:
-
URI প্যাটার্ন যদি একটি সারির জন্য হয়:
android.cursor.item/ -
URI প্যাটার্ন একাধিক সারির জন্য হলে:
android.cursor.dir/
-
URI প্যাটার্ন যদি একটি সারির জন্য হয়:
-
প্রদানকারী-নির্দিষ্ট অংশ:
vnd.<name>।<type>আপনি
<name>ও<type>সরবরাহ করেন।<name>ভ্যালু বিশ্বব্যাপী অনন্য, এবং<type>ভ্যালু সংশ্লিষ্ট URI প্যাটার্নের জন্য অনন্য।<name>-এর জন্য আপনার কোম্পানির নাম বা আপনার অ্যাপ্লিকেশনের Android প্যাকেজের নামের কিছু অংশ বেছে নেওয়া ভাল।<type>-এর জন্য একটি ভাল বিকল্প হল এমন একটি স্ট্রিং যা URI-এর সাথে যুক্ত টেবিলকে শনাক্ত করে।
যেমন, কোনও প্রোভাইডারের অথরিটি যদি
com.example.app.provider হয় এবং এটি
table1 নামের একটি টেবিল দেখায়, তাহলে table1-এ একাধিক সারির জন্য MIME-এর প্রকার হল:
vnd.android.cursor.dir/vnd.com.example.provider.table1
table1-এর একটি সারির জন্য, MIME-এর ধরন হল:
vnd.android.cursor.item/vnd.com.example.provider.table1
ফাইলের জন্য MIME-এর ধরন
আপনার পরিষেবা প্রদানকারী ফাইল অফার করলে, getStreamTypes() প্রয়োগ করুন।
এই পদ্ধতিটি আপনার প্রদানকারীর ফাইলের জন্য MIME প্রকারের একটি String অ্যারে প্রদান করে
প্রদত্ত কন্টেন্ট URI-এর জন্য ফেরত দিতে পারে। MIME-এর প্রকার ফিল্টার আর্গুমেন্ট ব্যবহার করে আপনার অফার করা MIME-এর প্রকার ফিল্টার করুন, যাতে আপনি শুধুমাত্র সেই MIME-এর প্রকারগুলি ফেরত দেন যা ক্লায়েন্ট ম্যানেজ করতে চায়।
যেমন, এমন কোনও পরিষেবা প্রদানকারীর কথা ভাবুন যারা JPG, PNG ও GIF ফর্ম্যাটে
ফাইল হিসেবে ফটো ইমেজ অফার করে।
কোনও অ্যাপ্লিকেশন যদি ContentResolver.getStreamTypes()-কে image/* ফিল্টার স্ট্রিং দিয়ে কল করে, এমন কিছুর জন্য যা "ছবি" হিসেবে চিহ্নিত,
তাহলে ContentProvider.getStreamTypes() পদ্ধতি এই অ্যারে রিটার্ন করে:
{ "image/jpeg", "image/png", "image/gif"}
অ্যাপটি যদি শুধুমাত্র JPG ফাইলের জন্য হয়, তাহলে এটি
ContentResolver.getStreamTypes()-কে *\/jpeg ফিল্টার স্ট্রিংয়ের সাথে কল করতে পারে এবং
getStreamTypes() এটি রিটার্ন করে:
{"image/jpeg"}
আপনার পরিষেবা প্রদানকারী ফিল্টার স্ট্রিংয়ে অনুরোধ করা MIME-এর প্রকারের কোনওটিই অফার না করলে,
getStreamTypes()
null রিটার্ন করে।
কনট্র্যাক্ট ক্লাস প্রয়োগ করা
কনট্র্যাক্ট ক্লাস হল একটি public final ক্লাস যাতে URI, কলামের নাম, MIME-এর প্রকার এবং
প্রদানকারীর সাথে সম্পর্কিত অন্যান্য মেটা-ডেটার জন্য কনস্ট্যান্ট সংজ্ঞা থাকে। ক্লাসটি
প্রদানকারী এবং অন্যান্য অ্যাপ্লিকেশনের মধ্যে একটি চুক্তি স্থাপন করে যাতে নিশ্চিত করা যায় যে প্রদানকারীকে
সঠিকভাবে অ্যাক্সেস করা যেতে পারে, এমনকি URI, কলামের নাম এবং আরও অনেক কিছুর প্রকৃত মান পরিবর্তন হলেও।
কনট্র্যাক্ট ক্লাস ডেভেলপারদেরও সাহায্য করে কারণ সাধারণত এর কনস্ট্যান্টের জন্য নেমোনিক নাম থাকে, তাই ডেভেলপারদের কলামের নাম বা URI-এর জন্য ভুল ভ্যালু ব্যবহার করার সম্ভাবনা কম থাকে। যেহেতু এটি একটি ক্লাস, তাই এতে Javadoc ডকুমেন্টেশন থাকতে পারে। Android Studio-র মতো ইন্টিগ্রেটেড ডেভেলপমেন্ট এনভায়রনমেন্ট কনট্র্যাক্ট ক্লাস থেকে কনস্ট্যান্টের নাম অটোমেটিক সম্পূর্ণ করতে এবং কনস্ট্যান্টের জন্য Javadoc দেখাতে পারে।
ডেভেলপাররা আপনার অ্যাপ্লিকেশন থেকে কনট্র্যাক্ট ক্লাসের ক্লাস ফাইল অ্যাক্সেস করতে পারবেন না, তবে তারা আপনার দেওয়া একটি JAR ফাইল থেকে তাদের অ্যাপ্লিকেশনে এটি স্ট্যাটিক্যালি কম্পাইল করতে পারবেন।
ContactsContract ক্লাস এবং এর নেস্টেড ক্লাস হল কনট্র্যাক্ট ক্লাসের
উদাহরণ।
কন্টেন্ট প্রোভাইডার সংক্রান্ত অনুমতি প্রয়োগ করুন
Android সিস্টেমের সব দিকের জন্য অনুমতি এবং অ্যাক্সেস সম্পর্কে বিস্তারিত বিবরণ নিরাপত্তা সংক্রান্ত পরামর্শ-এ দেওয়া আছে। এছাড়াও, ডেটা ও ফাইল স্টোরেজ ওভারভিউ থেকে বিভিন্ন ধরনের স্টোরেজের ক্ষেত্রে প্রযোজ্য নিরাপত্তা ও অনুমতির ব্যাপারে জানতে পারবেন। সংক্ষেপে, গুরুত্বপূর্ণ পয়েন্টগুলি নিচে উল্লেখ করা হল:
- ডিফল্ট হিসেবে, ডিভাইসের ইন্টার্নাল স্টোরেজে সেভ করা ডেটা ফাইল আপনার অ্যাপ্লিকেশন ও পরিষেবা প্রদানকারীর জন্য ব্যক্তিগত থাকে।
-
আপনার তৈরি করা
SQLiteDatabaseডেটাবেস আপনার অ্যাপ্লিকেশন ও পরিষেবা প্রদানকারীর কাছে ব্যক্তিগত থাকে। - ডিফল্ট হিসেবে, এক্সটার্নাল স্টোরেজে সেভ করা ডেটা ফাইল পাবলিক এবং বিশ্বের যে কেউ পড়তে পারবেন। আপনি এক্সটার্নাল স্টোরেজে ফাইলের অ্যাক্সেস সীমাবদ্ধ করতে কন্টেন্ট প্রোভাইডার ব্যবহার করতে পারবেন না, কারণ অন্যান্য অ্যাপ্লিকেশন সেগুলি পড়তে এবং লিখতে অন্যান্য API কল ব্যবহার করতে পারে।
- আপনার ডিভাইসের ইন্টার্নাল স্টোরেজে ফাইল বা SQLite ডেটাবেস খোলা বা তৈরি করার জন্য মেথড কল সম্ভাব্যভাবে অন্য সব অ্যাপ্লিকেশনকে রিড ও রাইট অ্যাক্সেস দিতে পারে। আপনি যদি কোনও ইন্টার্নাল ফাইল বা ডেটাবেসকে আপনার প্রোভাইডারের রিপোজিটরি হিসেবে ব্যবহার করেন এবং সেটিকে "world-readable" বা "world-writeable" অ্যাক্সেস দেন, তাহলে ম্যানিফেস্টে আপনার প্রোভাইডারের জন্য সেট করা অনুমতি আপনার ডেটা সুরক্ষিত করে না। ইন্টার্নাল স্টোরেজে ফাইল ও ডেটাবেসের জন্য ডিফল্ট অ্যাক্সেস হল "ব্যক্তিগত"; আপনার পরিষেবা প্রদানকারীর রিপোজিটরির জন্য এটি পরিবর্তন করবেন না।
আপনার ডেটার অ্যাক্সেস নিয়ন্ত্রণ করার জন্য কন্টেন্ট প্রোভাইডারের অনুমতি ব্যবহার করতে চাইলে, আপনার ডেটা ইন্টার্নাল ফাইল, SQLite ডেটাবেস বা ক্লাউডে, যেমন রিমোট সার্ভারে স্টোর করুন এবং ফাইল ও ডেটাবেস আপনার অ্যাপ্লিকেশনের জন্য ব্যক্তিগত রাখুন।
অনুমতি প্রয়োগ করা
ডিফল্ট হিসেবে, সব অ্যাপ্লিকেশন আপনার প্রোভাইডার থেকে ডেটা রিড বা রাইট করতে পারে, এমনকি অন্তর্নিহিত ডেটা
ব্যক্তিগত হলেও, কারণ ডিফল্ট হিসেবে আপনার প্রোভাইডারের অনুমতি সেট করা থাকে না। এটি পরিবর্তন করতে,
<provider> এলিমেন্টের অ্যাট্রিবিউট বা চাইল্ড এলিমেন্ট ব্যবহার করে, আপনার ম্যানিফেস্ট ফাইলে
প্রোভাইডারের জন্য অনুমতি সেট করুন। আপনি এমন অনুমতি সেট করতে পারেন যা সম্পূর্ণ প্রদানকারী,
নির্দিষ্ট টেবিল, নির্দিষ্ট রেকর্ড বা তিনটির ক্ষেত্রেই প্রযোজ্য হয়।
আপনার ম্যানিফেস্ট ফাইলে এক বা একাধিক
<permission> এলিমেন্টের মাধ্যমে
আপনার পরিষেবা প্রদানকারীর জন্য অনুমতি নির্ধারণ করুন। আপনার পরিষেবা প্রদানকারীর জন্য
অনুমতি অনন্য করতে,
android:name অ্যাট্রিবিউটের জন্য
জাভা-স্টাইল স্কোপিং ব্যবহার করুন। যেমন, রিড পার্মিশনের নাম দিন
com.example.app.provider.permission.READ_PROVIDER।
নিম্নলিখিত তালিকাটি প্রদানকারীর অনুমতির পরিধি বর্ণনা করে, যা শুরু হয় সম্পূর্ণ প্রদানকারীর ক্ষেত্রে প্রযোজ্য অনুমতি দিয়ে এবং তারপর আরও সূক্ষ্ম হয়ে ওঠে। আরও সূক্ষ্ম-গ্রেনড অনুমতিগুলি বৃহত্তর সুযোগের সাথে অগ্রাধিকার নেয়।
- প্রোভাইডার-লেভেলে একবার রিড-রাইট করার অনুমতি
-
একটি অনুমতি যা সম্পূর্ণ প্রদানকারীর রিড ও রাইট অ্যাক্সেস নিয়ন্ত্রণ করে,
<provider>এলিমেন্টেরandroid:permissionঅ্যাট্রিবিউটের মাধ্যমে নির্দিষ্ট করা হয়। - প্রোভাইডার-লেভেল অনুমতি আলাদা করে রিড ও রাইট করুন
-
সম্পূর্ণ প্রোভাইডারের জন্য রিড পার্মিশন ও রাইট পার্মিশন। আপনি
<provider>এলিমেন্টেরandroid:readPermissionএবংandroid:writePermissionঅ্যাট্রিবিউটের মাধ্যমে সেগুলি উল্লেখ করেন।android:permission-এর জন্য প্রয়োজনীয় অনুমতির চেয়ে এগুলি বেশি গুরুত্বপূর্ণ। - পাথ-লেভেল অনুমতি
-
আপনার প্রদানকারীর কন্টেন্ট URI-এর জন্য রিড, রাইট বা রিড/রাইট করার অনুমতি। আপনি
<provider>এলিমেন্টের<path-permission>চাইল্ড এলিমেন্টের মাধ্যমে নিয়ন্ত্রণ করতে চান এমন প্রতিটি URI উল্লেখ করেন। আপনার উল্লেখ করা প্রতিটি কন্টেন্ট URI-এর জন্য, আপনি একটি রিড/রাইট পার্মিশন, একটি রিড পার্মিশন, একটি রাইট পার্মিশন বা তিনটিই উল্লেখ করতে পারেন। রিড/রাইট পার্মিশনের চেয়ে রিড অ্যান্ড রাইট পার্মিশন বেশি প্রাধান্য পায়। এছাড়াও, পাথ-লেভেল অনুমতি, প্রদানকারী-লেভেল অনুমতির চেয়ে বেশি অগ্রাধিকার পায়। - টেম্পোরারি পারমিশন
-
এমন একটি অনুমতির লেভেল যা কোনও অ্যাপ্লিকেশনকে সাময়িক অ্যাক্সেস প্রদান করে, এমনকি অ্যাপ্লিকেশনটির কাছে
সাধারণত প্রয়োজনীয় অনুমতি না থাকলেও। সাময়িক
অ্যাক্সেস ফিচারটি কোনও অ্যাপ্লিকেশনের ম্যানিফেস্টে অনুরোধ করা অনুমতির সংখ্যা
কমায়। আপনি টেম্পোরারি পারমিশন চালু করলে, আপনার পরিষেবা প্রদানকারীর জন্য শুধুমাত্র সেইসব অ্যাপ্লিকেশনের
স্থায়ী অনুমতি প্রয়োজন হয় যেগুলি আপনার সব ডেটা
ক্রমাগত অ্যাক্সেস করে।
যেমন, আপনি যদি কোনও ইমেল পরিষেবা প্রদানকারী এবং অ্যাপের জন্য অনুমতি সেট করেন এবং আপনি বাইরের কোনও ইমেজ ভিউয়ার অ্যাপ্লিকেশনকে আপনার পরিষেবা প্রদানকারীর থেকে ফটো অ্যাটাচমেন্ট দেখাতে দিতে চান, তাহলে আপনার কী কী অনুমতি প্রয়োজন তা বিবেচনা করুন। অনুমতির প্রয়োজন ছাড়াই ইমেজ ভিউয়ারকে প্রয়োজনীয় অ্যাক্সেস দিতে, আপনি ফটোর জন্য কন্টেন্ট URI-তে সাময়িক অনুমতি সেট-আপ করতে পারেন।
আপনার ইমেল অ্যাপ এমনভাবে ডিজাইন করুন যাতে ব্যবহারকারী কোনও ফটো দেখাতে চাইলে, অ্যাপটি ফটো কন্টেন্টের URI এবং অনুমতি ফ্ল্যাগ সহ একটি ইনটেন্ট ইমেজ ভিউয়ারে পাঠায়। ইমেজ ভিউয়ার তখন ফটো ফিরিয়ে আনার জন্য আপনার ইমেল পরিষেবা প্রদানকারীকে কোয়েরি করতে পারে, যদিও ভিউয়ারের কাছে আপনার পরিষেবা প্রদানকারীর জন্য সাধারণ রিড পার্মিশন নেই।
টেম্পোরারি পারমিশন চালু করতে, হয়
<provider>এলিমেন্টেরandroid:grantUriPermissionsঅ্যাট্রিবিউট সেট করুন অথবা আপনার<provider>এলিমেন্টে এক বা একাধিক<grant-uri-permission>চাইল্ড এলিমেন্ট যোগ করুন। আপনার প্রোভাইডার থেকে টেম্পোরারি পারমিশনের সাথে যুক্ত কন্টেন্ট URI-এর জন্য সহায়তা সরিয়ে দেওয়ার সময়Context.revokeUriPermission()কল করুন।অ্যাট্রিবিউটের ভ্যালু নির্ধারণ করে যে আপনার প্রদানকারীর কতটা অ্যাক্সেসযোগ্য করা হয়েছে। অ্যাট্রিবিউট
"true"-এ সেট করা থাকলে, সিস্টেম আপনার সম্পূর্ণ প্রোভাইডারকে সাময়িক অনুমতি দেয়, প্রোভাইডার-লেভেল বা পাথ-লেভেল অনুমতির জন্য প্রয়োজনীয় অন্য যেকোনও অনুমতিকে ওভাররাইড করে।এই ফ্ল্যাগ
"false"-এ সেট করা থাকলে, আপনার<provider>এলিমেন্টে<grant-uri-permission>চাইল্ড এলিমেন্ট যোগ করুন। প্রতিটি চাইল্ড এলিমেন্ট কন্টেন্ট URI বা URI নির্দিষ্ট করে যার জন্য সাময়িক অ্যাক্সেস মঞ্জুর করা হয়।কোনও অ্যাপ্লিকেশনকে সাময়িক অ্যাক্সেস ডেলিগেট করতে, ইনটেন্টে অবশ্যই
FLAG_GRANT_READ_URI_PERMISSIONফ্ল্যাগ,FLAG_GRANT_WRITE_URI_PERMISSIONফ্ল্যাগ অথবা দুটিই থাকতে হবে। এগুলিsetFlags()পদ্ধতিতে সেট করা হয়।android:grantUriPermissionsঅ্যাট্রিবিউট না থাকলে, এটি"false"হিসেবে ধরে নেওয়া হয়।
<provider> এলিমেন্ট
Activity এবং Service কম্পোনেন্টের মতো,
ContentProvider-এর একটি সাবক্লাস
<provider> এলিমেন্ট ব্যবহার করে, এর অ্যাপ্লিকেশনের জন্য ম্যানিফেস্ট ফাইলে
সংজ্ঞায়িত করা হয়। Android সিস্টেম এলিমেন্ট থেকে নিম্নলিখিত তথ্য
পায়:
-
কর্তৃপক্ষ
(
android:authorities) - সিস্টেমের মধ্যে সম্পূর্ণ পরিষেবা প্রদানকারীকে শনাক্ত করে এমন প্রতীকী নাম। এই অ্যাট্রিবিউট সম্পর্কে আরও বিস্তারিত বিবরণ কন্টেন্ট URI ডিজাইন করুন বিভাগে দেওয়া আছে।
-
প্রোভাইডার ক্লাস নেম
(
android:name) -
ContentProviderপ্রয়োগ করে এমন ক্লাস। এই ক্লাসটি ContentProvider ক্লাস প্রয়োগ করুন বিভাগে আরও বিস্তারিতভাবে বর্ণনা করা হয়েছে। - অনুমতি
-
প্রোভাইডারের ডেটা অ্যাক্সেস করার জন্য অন্যান্য অ্যাপ্লিকেশনের কাছে অবশ্যই থাকতে হবে এমন অনুমতি নির্দিষ্ট করে
যে অ্যাট্রিবিউট:
-
android:grantUriPermissions: টেম্পোরারি পারমিশন ফ্ল্যাগ -
android:permission: একটি প্রদানকারী-ব্যাপী রিড/রাইট পার্মিশন -
android:readPermission: প্রোভাইডার-ওয়াইড রিড পার্মিশন -
android:writePermission: প্রোভাইডার-ওয়াইড রাইট পার্মিশন
অনুমতি এবং তাদের সংশ্লিষ্ট অ্যাট্রিবিউট সম্পর্কে আরও বিস্তারিত বিবরণ কন্টেন্ট প্রোভাইডার সংক্রান্ত অনুমতি প্রয়োগ করুন বিভাগে দেওয়া আছে।
-
- স্টার্টআপ ও কন্ট্রোল অ্যাট্রিবিউট
-
এইসব অ্যাট্রিবিউট নির্ধারণ করে যে Android সিস্টেম কীভাবে এবং কখন প্রোভাইডার, প্রোভাইডারের প্রসেস বৈশিষ্ট্য
এবং অন্যান্য রানটাইম সেটিংস শুরু করে:
-
android:enabled: সিস্টেমকে প্রোভাইডার চালু করার অনুমতি দেওয়ার ফ্ল্যাগ -
android:exported: ফ্ল্যাগ যা অন্যান্য অ্যাপ্লিকেশনকে এই পরিষেবা প্রদানকারীকে ব্যবহার করতে দেয় -
android:initOrder: একই প্রসেসে অন্যান্য প্রোভাইডারের তুলনায় এই প্রোভাইডার যে ক্রমে শুরু হয় -
android:multiProcess: ফ্ল্যাগ যা সিস্টেমকে কলিং ক্লায়েন্টের মতো একই প্রসেসে প্রোভাইডারকে শুরু করতে দেয় -
android:process: যে প্রসেসে পরিষেবা প্রদানকারী রান করে তার নাম -
android:syncable: ফ্ল্যাগ যা নির্দেশ করে যে পরিষেবা প্রদানকারীর ডেটা সার্ভারের ডেটার সাথে সিঙ্ক করতে হবে
এইসব অ্যাট্রিবিউট
<provider>এলিমেন্টের গাইডে সম্পূর্ণভাবে ডকুমেন্ট করা আছে। -
- তথ্যমূলক অ্যাট্রিবিউট
-
পরিষেবা প্রদানকারীর জন্য একটি ঐচ্ছিক আইকন এবং লেবেল:
-
android:icon: ড্রয়েবল রিসোর্স যাতে পরিষেবা প্রদানকারীর আইকন আছে। সেটিংস > অ্যাপ > সব বিকল্পে গিয়ে অ্যাপের তালিকায় পরিষেবা প্রদানকারীর লেবেলের পাশে আইকনটি দেখা যায়। -
android:label: তথ্যমূলক লেবেল যা পরিষেবা প্রদানকারী, তার ডেটা বা উভয় সম্পর্কে বর্ণনা করে। লেবেলটি সেটিংস > অ্যাপ > সব বিকল্পে অ্যাপের তালিকায় দেখা যায়।
এইসব অ্যাট্রিবিউট
<provider>এলিমেন্টের গাইডে সম্পূর্ণভাবে ডকুমেন্ট করা আছে। -
মনে রাখবেন: আপনি Android 11 বা তার পরবর্তী ভার্সন টার্গেট করলে, আরও কনফিগারেশনের জন্য প্যাকেজ দৃশ্যমানতা সংক্রান্ত ডকুমেন্টেশন দেখুন।
ইনটেন্ট ও ডেটা অ্যাক্সেস
অ্যাপ্লিকেশন Intent-এর মাধ্যমে পরোক্ষভাবে কন্টেন্ট প্রোভাইডার অ্যাক্সেস করতে পারে।
অ্যাপ্লিকেশনটি ContentResolver বা
ContentProvider-এর কোনও পদ্ধতি কল করে না। পরিবর্তে, এটি একটি ইনটেন্ট পাঠায় যা একটি অ্যাক্টিভিটি শুরু করে,
যা প্রায়শই পরিষেবা প্রদানকারীর নিজস্ব অ্যাপ্লিকেশনের অংশ। গন্তব্য অ্যাক্টিভিটি তার UI-তে ডেটা ফিরিয়ে আনা এবং দেখানোর
দায়িত্বে থাকে।
ইনটেন্টের অ্যাকশনের উপর নির্ভর করে, ডেস্টিনেশন অ্যাক্টিভিটি ব্যবহারকারীকে প্রোভাইডারের ডেটা পরিবর্তন করার জন্য প্রম্পট করতে পারে। এছাড়াও, ইনটেন্টে "অতিরিক্ত" ডেটা থাকতে পারে যা ডেস্টিনেশন অ্যাক্টিভিটি UI-তে দেখায়। ব্যবহারকারী তখন এই ডেটা ব্যবহার করে পরিষেবা প্রদানকারীর ডেটা পরিবর্তন করার আগে এই ডেটা পরিবর্তন করার বিকল্প পান।
ডেটা ইন্টিগ্রিটির ক্ষেত্রে সাহায্য করতে আপনি ইনটেন্ট অ্যাক্সেস ব্যবহার করতে পারেন। আপনার পরিষেবা প্রদানকারী, কঠোরভাবে সংজ্ঞায়িত ব্যবসায়িক যুক্তি অনুযায়ী ডেটা যোগ, আপডেট এবং মুছে ফেলার উপর নির্ভর করতে পারে। যদি এমন হয়, তাহলে অন্যান্য অ্যাপ্লিকেশনকে সরাসরি আপনার ডেটা পরিবর্তন করতে দিলে ভুল ডেটা তৈরি হতে পারে।
আপনি যদি চান যে ডেভেলপাররা ইনটেন্ট অ্যাক্সেস ব্যবহার করুক, তাহলে এটি পুঙ্খানুপুঙ্খভাবে ডকুমেন্ট করতে ভুলবেন না। আপনার অ্যাপ্লিকেশনের UI ব্যবহার করে ইনটেন্ট অ্যাক্সেস করা কেন তাদের কোড দিয়ে ডেটা পরিবর্তন করার চেষ্টা করার চেয়ে ভালো তা ব্যাখ্যা করুন।
আপনার পরিষেবা প্রদানকারীর ডেটা পরিবর্তন করতে চায় এমন ইনকামিং ইনটেন্ট ম্যানেজ করা অন্য ইনটেন্ট ম্যানেজ করার থেকে আলাদা নয়। আপনি ইনটেন্ট ও ইনটেন্ট ফিল্টার পড়ে ইনটেন্ট ব্যবহার করার ব্যাপারে আরও জানতে পারবেন।
আরও সম্পর্কিত তথ্যের জন্য, Calendar প্রদানকারীর ওভারভিউ দেখুন।