বিষয়বস্তু প্রদানকারী বেসিক

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

সাধারণত আপনি দুটি পরিস্থিতির একটিতে বিষয়বস্তু সরবরাহকারীদের সাথে কাজ করেন: অন্য অ্যাপ্লিকেশনে বিদ্যমান সামগ্রী সরবরাহকারীকে অ্যাক্সেস করার জন্য কোড প্রয়োগ করা বা অন্যান্য অ্যাপ্লিকেশনের সাথে ডেটা ভাগ করার জন্য আপনার অ্যাপ্লিকেশনটিতে একটি নতুন সামগ্রী সরবরাহকারী তৈরি করা।

এই পৃষ্ঠাটি বিদ্যমান বিষয়বস্তু প্রদানকারীদের সাথে কাজ করার মৌলিক বিষয়গুলি কভার করে৷ আপনার নিজের অ্যাপ্লিকেশনে বিষয়বস্তু প্রদানকারীদের বাস্তবায়ন সম্পর্কে জানতে, একটি সামগ্রী প্রদানকারী তৈরি করুন দেখুন।

এই বিষয় নিম্নলিখিত বর্ণনা করে:

  • বিষয়বস্তু প্রদানকারীরা কিভাবে কাজ করে।
  • একটি বিষয়বস্তু প্রদানকারীর থেকে ডেটা পুনরুদ্ধার করতে আপনি যে API ব্যবহার করেন।
  • একটি বিষয়বস্তু প্রদানকারীতে ডেটা সন্নিবেশ, আপডেট বা মুছে ফেলার জন্য আপনি যে API ব্যবহার করেন।
  • অন্যান্য API বৈশিষ্ট্য যা প্রদানকারীদের সাথে কাজ করার সুবিধা দেয়।

ওভারভিউ

একটি বিষয়বস্তু প্রদানকারী বহিরাগত অ্যাপ্লিকেশনের কাছে এক বা একাধিক টেবিল হিসাবে ডেটা উপস্থাপন করে যা একটি রিলেশনাল ডাটাবেসে পাওয়া টেবিলের অনুরূপ। একটি সারি প্রদানকারী সংগ্রহ করা কিছু ধরণের ডেটার একটি উদাহরণ উপস্থাপন করে এবং সারির প্রতিটি কলাম একটি উদাহরণের জন্য সংগ্রহ করা ডেটার একটি পৃথক অংশকে উপস্থাপন করে।

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

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

চিত্র 1. একটি বিষয়বস্তু প্রদানকারী এবং অন্যান্য উপাদানের মধ্যে সম্পর্ক।

একটি প্রদানকারী অ্যাক্সেস

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

প্রদানকারী বস্তুটি ক্লায়েন্টদের কাছ থেকে ডেটা অনুরোধ গ্রহণ করে, অনুরোধকৃত ক্রিয়া সম্পাদন করে এবং ফলাফল প্রদান করে। এই বস্তুটির এমন পদ্ধতি রয়েছে যা প্রদানকারী অবজেক্টে অভিন্নভাবে নামকরণ করা পদ্ধতিগুলিকে কল করে, যা ContentProvider এর কংক্রিট সাবক্লাসগুলির একটির উদাহরণ। ContentResolver পদ্ধতিগুলি স্থায়ী স্টোরেজের মৌলিক "CRUD" (তৈরি, পুনরুদ্ধার, আপডেট এবং মুছে ফেলা) ফাংশন প্রদান করে।

আপনার UI থেকে একটি ContentProvider অ্যাক্সেস করার জন্য একটি সাধারণ প্যাটার্ন ব্যাকগ্রাউন্ডে একটি অ্যাসিঙ্ক্রোনাস ক্যোয়ারী চালানোর জন্য একটি CursorLoader ব্যবহার করে। আপনার UI-এর Activity বা Fragment ক্যোয়ারীতে একটি CursorLoader কল করে, যা ফলস্বরূপ ContentResolver ব্যবহার করে ContentProvider পায়।

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

ContentProvider, অন্যান্য ক্লাস এবং স্টোরেজের মধ্যে মিথস্ক্রিয়া।

চিত্র 2. ContentProvider , অন্যান্য শ্রেণী এবং সঞ্চয়স্থানের মধ্যে মিথস্ক্রিয়া।

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

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

সারণি 1: নমুনা ব্যবহারকারী অভিধান টেবিল।

শব্দ অ্যাপ আইডি ফ্রিকোয়েন্সি লোকেল _আইডি
mapreduce ব্যবহারকারী1 100 en_US 1
precompiler ব্যবহারকারী14 200 fr_FR 2
applet ব্যবহারকারী2 225 fr_CA 3
const ব্যবহারকারী1 255 pt_BR 4
int ব্যবহারকারী5 100 en_UK 5

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

ব্যবহারকারী অভিধান প্রদানকারী থেকে শব্দ এবং তাদের লোকেলের একটি তালিকা পেতে, আপনি ContentResolver.query() কল করুন। query() পদ্ধতিটি ব্যবহারকারী অভিধান প্রদানকারী দ্বারা সংজ্ঞায়িত ContentProvider.query() পদ্ধতিকে কল করে। কোডের নিম্নলিখিত লাইনগুলি একটি ContentResolver.query() কল দেখায়:

কোটলিন

// Queries the UserDictionary and returns results
cursor = contentResolver.query(
        UserDictionary.Words.CONTENT_URI,  // The content URI of the words table
        projection,                        // The columns to return for each row
        selectionClause,                   // Selection criteria
        selectionArgs.toTypedArray(),      // Selection criteria
        sortOrder                          // The sort order for the returned rows
)

জাভা

// Queries the UserDictionary and returns results
cursor = getContentResolver().query(
    UserDictionary.Words.CONTENT_URI,  // The content URI of the words table
    projection,                        // The columns to return for each row
    selectionClause,                   // Selection criteria
    selectionArgs,                     // Selection criteria
    sortOrder);                        // The sort order for the returned rows

সারণি 2 দেখায় কিভাবে query(Uri,projection,selection,selectionArgs,sortOrder) একটি SQL SELECT স্টেটমেন্টের সাথে মেলে:

সারণি 2: query() SQL কোয়েরির তুলনায়।

query() আর্গুমেন্ট কীওয়ার্ড/প্যারামিটার নির্বাচন করুন নোট
Uri FROM table_name Uri টেবিলে মানচিত্র প্রদানকারীর নাম table_name
projection col,col,col,... projection হল কলামগুলির একটি অ্যারে যা পুনরুদ্ধার করা প্রতিটি সারির জন্য অন্তর্ভুক্ত করা হয়।
selection WHERE col = value selection সারি নির্বাচনের মানদণ্ড নির্দিষ্ট করে।
selectionArgs কোন সঠিক সমতুল্য. নির্বাচন যুক্তি প্রতিস্থাপন ? নির্বাচন ধারায় স্থানধারক।
sortOrder ORDER BY col,col,... sortOrder ফেরত দেওয়া Cursor কোন সারি প্রদর্শিত হবে তা নির্দিষ্ট করে।

বিষয়বস্তু URI

একটি বিষয়বস্তু URI হল একটি URI যা একটি প্রদানকারীর ডেটা সনাক্ত করে। বিষয়বস্তু URI-তে সমগ্র প্রদানকারীর প্রতীকী নাম—তার কর্তৃপক্ষ —এবং একটি নাম যা একটি টেবিলের দিকে নির্দেশ করে—একটি পথ । আপনি যখন একটি সরবরাহকারীতে একটি টেবিল অ্যাক্সেস করার জন্য একটি ক্লায়েন্ট পদ্ধতি কল করেন, তখন টেবিলের জন্য বিষয়বস্তু URI হল একটি আর্গুমেন্ট।

কোডের পূর্ববর্তী লাইনে, ধ্রুবক CONTENT_URI ব্যবহারকারী অভিধান প্রদানকারীর Words টেবিলের বিষয়বস্তু URI ধারণ করে। ContentResolver অবজেক্ট URI-এর কর্তৃত্বকে বিশ্লেষণ করে এবং পরিচিত প্রদানকারীদের একটি সিস্টেম টেবিলের সাথে কর্তৃপক্ষের তুলনা করে প্রদানকারীর সমাধান করতে এটি ব্যবহার করে। ContentResolver তারপর সঠিক প্রদানকারীর কাছে ক্যোয়ারী আর্গুমেন্ট পাঠাতে পারে।

ContentProvider কন্টেন্ট URI-এর পাথ অংশ ব্যবহার করে অ্যাক্সেস করার জন্য টেবিল বেছে নেয়। একটি প্রদানকারীর সাধারণত প্রতিটি টেবিলের জন্য একটি পথ থাকে যা এটি প্রকাশ করে।

কোডের পূর্ববর্তী লাইনগুলিতে, Words টেবিলের জন্য সম্পূর্ণ URI হল:

content://user_dictionary/words
  • content:// স্ট্রিং হল স্কিম , যা সর্বদা উপস্থিত থাকে এবং এটিকে একটি বিষয়বস্তু URI হিসাবে চিহ্নিত করে।
  • user_dictionary স্ট্রিং হল প্রদানকারীর কর্তৃত্ব।
  • words স্ট্রিং হল টেবিলের পথ।

অনেক প্রদানকারী আপনাকে URI-এর শেষে একটি ID মান যুক্ত করে একটি টেবিলে একটি একক সারি অ্যাক্সেস করতে দেয়। উদাহরণস্বরূপ, ব্যবহারকারী অভিধান প্রদানকারী থেকে একটি সারি পুনরুদ্ধার করতে যার _ID 4 , আপনি এই সামগ্রী URI ব্যবহার করতে পারেন:

কোটলিন

val singleUri: Uri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI, 4)

জাভা

Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4);

আপনি প্রায়ই আইডি মান ব্যবহার করেন যখন আপনি সারিগুলির একটি সেট পুনরুদ্ধার করেন এবং তারপর সেগুলির একটিকে আপডেট করতে বা মুছতে চান।

দ্রষ্টব্য: Uri এবং Uri.Builder ক্লাসে স্ট্রিং থেকে সুগঠিত URI অবজেক্ট তৈরির সুবিধার পদ্ধতি রয়েছে। ContentUris ক্লাসে একটি URI-তে ID মান যুক্ত করার সুবিধার পদ্ধতি রয়েছে। পূর্ববর্তী স্নিপেট ব্যবহারকারী অভিধান প্রদানকারী বিষয়বস্তু URI-তে একটি ID যুক্ত করতে withAppendedId() ব্যবহার করে।

প্রদানকারী থেকে তথ্য পুনরুদ্ধার করুন

এই বিভাগে একটি উদাহরণ হিসাবে ব্যবহারকারী অভিধান প্রদানকারী ব্যবহার করে একটি প্রদানকারী থেকে তথ্য পুনরুদ্ধার কিভাবে বর্ণনা করে।

স্পষ্টতার জন্য, এই বিভাগে কোড স্নিপেটগুলি UI থ্রেডে ContentResolver.query() কল করে। প্রকৃত কোডে, তবে, একটি পৃথক থ্রেডে অ্যাসিঙ্ক্রোনাসভাবে প্রশ্নগুলি করুন। আপনি CursorLoader ক্লাস ব্যবহার করতে পারেন, যা লোডার গাইডে আরও বিশদে বর্ণনা করা হয়েছে। এছাড়াও, কোডের লাইনগুলি শুধুমাত্র স্নিপেট। তারা একটি সম্পূর্ণ আবেদন দেখায় না.

একটি প্রদানকারীর থেকে ডেটা পুনরুদ্ধার করতে, এই মৌলিক পদক্ষেপগুলি অনুসরণ করুন:

  1. প্রদানকারীর জন্য পড়ার অ্যাক্সেসের অনুমতির অনুরোধ করুন।
  2. কোডটি সংজ্ঞায়িত করুন যা প্রদানকারীকে একটি প্রশ্ন পাঠায়।

পড়ার অ্যাক্সেসের অনুমতির অনুরোধ করুন

একটি প্রদানকারীর কাছ থেকে ডেটা পুনরুদ্ধার করতে, আপনার অ্যাপ্লিকেশন প্রদানকারীর জন্য পড়ার অ্যাক্সেসের অনুমতি প্রয়োজন৷ আপনি রানটাইমে এই অনুমতির অনুরোধ করতে পারবেন না। পরিবর্তে, আপনাকে <uses-permission> উপাদান এবং প্রদানকারীর দ্বারা সংজ্ঞায়িত সঠিক অনুমতি নাম ব্যবহার করে আপনার ম্যানিফেস্টে এই অনুমতির প্রয়োজন আছে তা উল্লেখ করতে হবে।

যখন আপনি আপনার ম্যানিফেস্টে এই উপাদানটি নির্দিষ্ট করেন, আপনি আপনার আবেদনের জন্য এই অনুমতির অনুরোধ করছেন৷ যখন ব্যবহারকারীরা আপনার অ্যাপ্লিকেশনটি ইনস্টল করেন, তখন তারা এই অনুরোধটি স্পষ্টভাবে মঞ্জুর করে।

আপনি যে প্রদানকারীর ব্যবহার করছেন তার রিড অ্যাক্সেস অনুমতির সঠিক নাম এবং সেইসাথে প্রদানকারীর দ্বারা ব্যবহৃত অন্যান্য অ্যাক্সেসের অনুমতিগুলির নামগুলি খুঁজে পেতে, প্রদানকারীর ডকুমেন্টেশন দেখুন৷

প্রদানকারীদের অ্যাক্সেস করার ক্ষেত্রে অনুমতির ভূমিকা বিষয়বস্তু প্রদানকারীর অনুমতি বিভাগে আরও বিস্তারিতভাবে বর্ণনা করা হয়েছে।

ব্যবহারকারী অভিধান প্রদানকারী তার ম্যানিফেস্ট ফাইলে অনুমতি android.permission.READ_USER_DICTIONARY সংজ্ঞায়িত করে, তাই একটি অ্যাপ্লিকেশন যা প্রদানকারীর কাছ থেকে পড়তে চায় তাকে অবশ্যই এই অনুমতির অনুরোধ করতে হবে।

প্রশ্নটি তৈরি করুন

একটি প্রদানকারীর থেকে ডেটা পুনরুদ্ধার করার পরবর্তী ধাপ হল একটি ক্যোয়ারী তৈরি করা। নিম্নলিখিত স্নিপেট ব্যবহারকারী অভিধান প্রদানকারী অ্যাক্সেস করার জন্য কিছু ভেরিয়েবল সংজ্ঞায়িত করে:

কোটলিন

// A "projection" defines the columns that are returned for each row
private val mProjection: Array<String> = arrayOf(
        UserDictionary.Words._ID,    // Contract class constant for the _ID column name
        UserDictionary.Words.WORD,   // Contract class constant for the word column name
        UserDictionary.Words.LOCALE  // Contract class constant for the locale column name
)

// Defines a string to contain the selection clause
private var selectionClause: String? = null

// Declares an array to contain selection arguments
private lateinit var selectionArgs: Array<String>

জাভা

// A "projection" defines the columns that are returned for each row
String[] mProjection =
{
    UserDictionary.Words._ID,    // Contract class constant for the _ID column name
    UserDictionary.Words.WORD,   // Contract class constant for the word column name
    UserDictionary.Words.LOCALE  // Contract class constant for the locale column name
};

// Defines a string to contain the selection clause
String selectionClause = null;

// Initializes an array to contain selection arguments
String[] selectionArgs = {""};

পরবর্তী স্নিপেটটি দেখায় কিভাবে ContentResolver.query() ব্যবহার করতে হয়, একটি উদাহরণ হিসাবে ব্যবহারকারী অভিধান প্রদানকারী ব্যবহার করে। একটি প্রদানকারী ক্লায়েন্ট ক্যোয়ারী একটি SQL ক্যোয়ারী অনুরূপ, এবং এটি কলামগুলির একটি সেট, নির্বাচনের মানদণ্ডের একটি সেট এবং একটি সাজানোর ক্রম ধারণ করে৷

কলামের যে সেটটি কোয়েরিটি ফেরত দেয় তাকে অভিক্ষেপ বলা হয় এবং ভেরিয়েবলটি হল mProjection

যে অভিব্যক্তিটি পুনরুদ্ধার করার জন্য সারিগুলি নির্দিষ্ট করে তা একটি নির্বাচন ধারা এবং নির্বাচন আর্গুমেন্টে বিভক্ত হয়। সিলেকশন ক্লজ হল লজিক্যাল এবং বুলিয়ান এক্সপ্রেশন, কলামের নাম এবং মানের সমন্বয়। পরিবর্তনশীল হল mSelectionClause . যদি আপনি প্রতিস্থাপনযোগ্য পরামিতি উল্লেখ করেন ? একটি মানের পরিবর্তে, ক্যোয়ারী পদ্ধতি নির্বাচন আর্গুমেন্ট অ্যারে থেকে মান পুনরুদ্ধার করে, যা পরিবর্তনশীল mSelectionArgs

পরবর্তী স্নিপেটে, ব্যবহারকারী একটি শব্দ না লিখলে নির্বাচন ধারাটি null সেট করা হয় এবং কোয়েরি প্রদানকারীর সমস্ত শব্দ ফেরত দেয়। যদি ব্যবহারকারী একটি শব্দ প্রবেশ করে, নির্বাচনের ধারাটি UserDictionary.Words.WORD + " = ?" এ সেট করা হয়। এবং নির্বাচন আর্গুমেন্ট অ্যারের প্রথম উপাদান ব্যবহারকারীর প্রবেশ করা শব্দ সেট করা হয়.

কোটলিন

/*
 * This declares a String array to contain the selection arguments.
 */
private lateinit var selectionArgs: Array<String>

// Gets a word from the UI
searchString = searchWord.text.toString()

// Insert code here to check for invalid or malicious input

// If the word is the empty string, gets everything
selectionArgs = searchString?.takeIf { it.isNotEmpty() }?.let {
    selectionClause = "${UserDictionary.Words.WORD} = ?"
    arrayOf(it)
} ?: run {
    selectionClause = null
    emptyArray<String>()
}

// Does a query against the table and returns a Cursor object
mCursor = contentResolver.query(
        UserDictionary.Words.CONTENT_URI, // The content URI of the words table
        projection,                       // The columns to return for each row
        selectionClause,                  // Either null or the word the user entered
        selectionArgs,                    // Either empty or the string the user entered
        sortOrder                         // The sort order for the returned rows
)

// Some providers return null if an error occurs, others throw an exception
when (mCursor?.count) {
    null -> {
        /*
         * Insert code here to handle the error. Be sure not to use the cursor!
         * You might want to call android.util.Log.e() to log this error.
         */
    }
    0 -> {
        /*
         * Insert code here to notify the user that the search is unsuccessful. This isn't
         * necessarily an error. You might want to offer the user the option to insert a new
         * row, or re-type the search term.
         */
    }
    else -> {
        // Insert code here to do something with the results
    }
}

জাভা

/*
 * This defines a one-element String array to contain the selection argument.
 */
String[] selectionArgs = {""};

// Gets a word from the UI
searchString = searchWord.getText().toString();

// Remember to insert code here to check for invalid or malicious input

// If the word is the empty string, gets everything
if (TextUtils.isEmpty(searchString)) {
    // Setting the selection clause to null returns all words
    selectionClause = null;
    selectionArgs[0] = "";

} else {
    // Constructs a selection clause that matches the word that the user entered
    selectionClause = UserDictionary.Words.WORD + " = ?";

    // Moves the user's input string to the selection arguments
    selectionArgs[0] = searchString;

}

// Does a query against the table and returns a Cursor object
mCursor = getContentResolver().query(
    UserDictionary.Words.CONTENT_URI, // The content URI of the words table
    projection,                       // The columns to return for each row
    selectionClause,                  // Either null or the word the user entered
    selectionArgs,                    // Either empty or the string the user entered
    sortOrder);                       // The sort order for the returned rows

// Some providers return null if an error occurs, others throw an exception
if (null == mCursor) {
    /*
     * Insert code here to handle the error. Be sure not to use the cursor! You can
     * call android.util.Log.e() to log this error.
     *
     */
// If the Cursor is empty, the provider found no matches
} else if (mCursor.getCount() < 1) {

    /*
     * Insert code here to notify the user that the search is unsuccessful. This isn't necessarily
     * an error. You can offer the user the option to insert a new row, or re-type the
     * search term.
     */

} else {
    // Insert code here to do something with the results

}

এই ক্যোয়ারীটি নিম্নলিখিত SQL স্টেটমেন্টের সাথে সাদৃশ্যপূর্ণ:

SELECT _ID, word, locale FROM words WHERE word = <userinput> ORDER BY word ASC;

এই SQL স্টেটমেন্টে, কন্ট্রাক্ট ক্লাস কনস্ট্যান্টের পরিবর্তে প্রকৃত কলামের নাম ব্যবহার করা হয়।

দূষিত ইনপুট থেকে রক্ষা করুন

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

নিম্নলিখিত নির্বাচন ধারা বিবেচনা করুন:

কোটলিন

// Constructs a selection clause by concatenating the user's input to the column name
var selectionClause = "var = $mUserInput"

জাভা

// Constructs a selection clause by concatenating the user's input to the column name
String selectionClause = "var = " + userInput;

আপনি যদি এটি করেন, আপনি ব্যবহারকারীকে সম্ভাব্যভাবে আপনার SQL স্টেটমেন্টে দূষিত SQL সংযুক্ত করতে দেন। উদাহরণস্বরূপ, ব্যবহারকারী "কিছুই নয়; ড্রপ টেবিল *;" লিখতে পারেন mUserInput এর জন্য , যার ফলাফল সিলেকশন ক্লজ var = nothing; DROP TABLE *; .

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

এই সমস্যা এড়াতে, একটি নির্বাচন ধারা ব্যবহার করুন যা ব্যবহার করে ? একটি প্রতিস্থাপনযোগ্য প্যারামিটার এবং নির্বাচন আর্গুমেন্টের একটি পৃথক অ্যারে হিসাবে। এইভাবে, ব্যবহারকারীর ইনপুট একটি SQL স্টেটমেন্টের অংশ হিসাবে ব্যাখ্যা করার পরিবর্তে সরাসরি প্রশ্নের সাথে আবদ্ধ হয়। যেহেতু এটি SQL হিসাবে বিবেচিত হয় না, ব্যবহারকারীর ইনপুট দূষিত SQL ইনজেকশন করতে পারে না। ব্যবহারকারীর ইনপুট অন্তর্ভুক্ত করার জন্য সংমিশ্রণ ব্যবহার করার পরিবর্তে, এই নির্বাচন ধারাটি ব্যবহার করুন:

কোটলিন

// Constructs a selection clause with a replaceable parameter
var selectionClause = "var = ?"

জাভা

// Constructs a selection clause with a replaceable parameter
String selectionClause =  "var = ?";

এই মত নির্বাচন আর্গুমেন্টের বিন্যাস সেট আপ করুন:

কোটলিন

// Defines a mutable list to contain the selection arguments
var selectionArgs: MutableList<String> = mutableListOf()

জাভা

// Defines an array to contain the selection arguments
String[] selectionArgs = {""};

এই মত নির্বাচন আর্গুমেন্ট অ্যারে একটি মান রাখুন:

কোটলিন

// Adds the user's input to the selection argument
selectionArgs += userInput

জাভা

// Sets the selection argument to the user's input
selectionArgs[0] = userInput;

একটি নির্বাচন ধারা ব্যবহার করে ? একটি প্রতিস্থাপনযোগ্য প্যারামিটার হিসাবে এবং একটি নির্বাচন আর্গুমেন্ট অ্যারে একটি নির্বাচন নির্দিষ্ট করার পছন্দের উপায়, এমনকি যদি প্রদানকারী SQL ডাটাবেসের উপর ভিত্তি করে না হয়।

ক্যোয়ারী ফলাফল প্রদর্শন করুন

ContentResolver.query() ক্লায়েন্ট পদ্ধতি সর্বদা একটি Cursor প্রদান করে যাতে কলামগুলি ক্যোয়ারির প্রজেকশন দ্বারা নির্দিষ্ট করা সারিগুলির জন্য যা ক্যোয়ারী নির্বাচনের মানদণ্ডের সাথে মেলে। একটি Cursor অবজেক্ট এতে থাকা সারি এবং কলামগুলিতে এলোমেলোভাবে পড়ার অ্যাক্সেস সরবরাহ করে।

Cursor পদ্ধতি ব্যবহার করে, আপনি ফলাফলের সারিগুলির উপর পুনরাবৃত্তি করতে পারেন, প্রতিটি কলামের ডেটা প্রকার নির্ধারণ করতে পারেন, একটি কলাম থেকে ডেটা বের করতে পারেন এবং ফলাফলের অন্যান্য বৈশিষ্ট্যগুলি পরীক্ষা করতে পারেন।

কিছু Cursor বাস্তবায়ন স্বয়ংক্রিয়ভাবে অবজেক্ট আপডেট করে যখন প্রদানকারীর ডেটা পরিবর্তিত হয়, যখন Cursor পরিবর্তন হয় তখন একটি পর্যবেক্ষক বস্তুতে ট্রিগার পদ্ধতি বা উভয়ই।

দ্রষ্টব্য: একটি প্রদানকারী কলামে অ্যাক্সেস সীমিত করতে পারে বস্তুর প্রকৃতির উপর ভিত্তি করে যে প্রশ্নটি করে। উদাহরণস্বরূপ, পরিচিতি প্রদানকারী অ্যাডাপ্টার সিঙ্ক করার জন্য কিছু কলামের অ্যাক্সেস সীমাবদ্ধ করে, তাই এটি তাদের একটি কার্যকলাপ বা পরিষেবাতে ফেরত দেয় না।

যদি কোনো সারি নির্বাচনের মানদণ্ডের সাথে মেলে না, তাহলে প্রদানকারী একটি Cursor বস্তু ফেরত দেয় যার জন্য Cursor.getCount() 0 হয়—অর্থাৎ একটি খালি কার্সার।

যদি একটি অভ্যন্তরীণ ত্রুটি ঘটে, প্রশ্নের ফলাফল নির্দিষ্ট প্রদানকারীর উপর নির্ভর করে। এটি null ফিরে আসতে পারে, অথবা এটি একটি Exception নিক্ষেপ করতে পারে।

যেহেতু একটি Cursor সারিগুলির একটি তালিকা, তাই একটি Cursor বিষয়বস্তু প্রদর্শন করার একটি ভাল উপায় হল একটি SimpleCursorAdapter ব্যবহার করে একটি ListView এর সাথে লিঙ্ক করা।

নিম্নলিখিত স্নিপেটটি আগের স্নিপেট থেকে কোডটি চালিয়ে যায়। এটি একটি SimpleCursorAdapter অবজেক্ট তৈরি করে যার মধ্যে Cursor ক্যোয়ারী দ্বারা পুনরুদ্ধার করা হয় এবং এই বস্তুটিকে একটি ListView এর জন্য অ্যাডাপ্টার হিসাবে সেট করে।

কোটলিন

// Defines a list of columns to retrieve from the Cursor and load into an output row
val wordListColumns : Array<String> = arrayOf(
        UserDictionary.Words.WORD,      // Contract class constant containing the word column name
        UserDictionary.Words.LOCALE     // Contract class constant containing the locale column name
)

// Defines a list of View IDs that receive the Cursor columns for each row
val wordListItems = intArrayOf(R.id.dictWord, R.id.locale)

// Creates a new SimpleCursorAdapter
cursorAdapter = SimpleCursorAdapter(
        applicationContext,             // The application's Context object
        R.layout.wordlistrow,           // A layout in XML for one row in the ListView
        mCursor,                        // The result from the query
        wordListColumns,                // A string array of column names in the cursor
        wordListItems,                  // An integer array of view IDs in the row layout
        0                               // Flags (usually none are needed)
)

// Sets the adapter for the ListView
wordList.setAdapter(cursorAdapter)

জাভা

// Defines a list of columns to retrieve from the Cursor and load into an output row
String[] wordListColumns =
{
    UserDictionary.Words.WORD,   // Contract class constant containing the word column name
    UserDictionary.Words.LOCALE  // Contract class constant containing the locale column name
};

// Defines a list of View IDs that receive the Cursor columns for each row
int[] wordListItems = { R.id.dictWord, R.id.locale};

// Creates a new SimpleCursorAdapter
cursorAdapter = new SimpleCursorAdapter(
    getApplicationContext(),               // The application's Context object
    R.layout.wordlistrow,                  // A layout in XML for one row in the ListView
    mCursor,                               // The result from the query
    wordListColumns,                       // A string array of column names in the cursor
    wordListItems,                         // An integer array of view IDs in the row layout
    0);                                    // Flags (usually none are needed)

// Sets the adapter for the ListView
wordList.setAdapter(cursorAdapter);

দ্রষ্টব্য: একটি Cursor সহ একটি ListView ব্যাক করতে, কার্সারে _ID নামে একটি কলাম থাকতে হবে। এই কারণে, পূর্বে দেখানো ক্যোয়ারীটি Words টেবিলের জন্য _ID কলাম পুনরুদ্ধার করে, যদিও ListView এটি প্রদর্শন করে না। এই নিষেধাজ্ঞাটি ব্যাখ্যা করে যে কেন বেশিরভাগ প্রদানকারীর তাদের প্রতিটি টেবিলের জন্য একটি _ID কলাম থাকে।

ক্যোয়ারী ফলাফল থেকে তথ্য পান

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

কোটলিন

/*
* Only executes if the cursor is valid. The User Dictionary Provider returns null if
* an internal error occurs. Other providers might throw an Exception instead of returning null.
*/
mCursor?.apply {
    // Determine the column index of the column named "word"
    val index: Int = getColumnIndex(UserDictionary.Words.WORD)

    /*
     * Moves to the next row in the cursor. Before the first movement in the cursor, the
     * "row pointer" is -1, and if you try to retrieve data at that position you get an
     * exception.
     */
    while (moveToNext()) {
        // Gets the value from the column
        newWord = getString(index)

        // Insert code here to process the retrieved word
        ...
        // End of while loop
    }
}

জাভা

// Determine the column index of the column named "word"
int index = mCursor.getColumnIndex(UserDictionary.Words.WORD);

/*
 * Only executes if the cursor is valid. The User Dictionary Provider returns null if
 * an internal error occurs. Other providers might throw an Exception instead of returning null.
 */

if (mCursor != null) {
    /*
     * Moves to the next row in the cursor. Before the first movement in the cursor, the
     * "row pointer" is -1, and if you try to retrieve data at that position you get an
     * exception.
     */
    while (mCursor.moveToNext()) {

        // Gets the value from the column
        newWord = mCursor.getString(index);

        // Insert code here to process the retrieved word
        ...
        // End of while loop
    }
} else {

    // Insert code here to report an error if the cursor is null or the provider threw an exception
}

Cursor বাস্তবায়নে অবজেক্ট থেকে বিভিন্ন ধরণের ডেটা পুনরুদ্ধারের জন্য বেশ কয়েকটি "পান" পদ্ধতি রয়েছে। উদাহরণস্বরূপ, পূর্ববর্তী স্নিপেট getString() ব্যবহার করে। তাদের একটি getType() পদ্ধতিও রয়েছে যা কলামের ডেটা প্রকার নির্দেশ করে একটি মান প্রদান করে।

রিলিজ ক্যোয়ারী ফলাফল সম্পদ

Cursor অবজেক্টগুলিকে অবশ্যই বন্ধ করতে হবে যদি সেগুলি আর প্রয়োজন না হয়, যাতে তাদের সাথে যুক্ত সংস্থানগুলি তাড়াতাড়ি মুক্তি পায়। এটি হয় close() কল করে, অথবা জাভা প্রোগ্রামিং ভাষায় try-with-resources স্টেটমেন্ট ব্যবহার করে বা কোটলিন প্রোগ্রামিং ভাষায় use() ফাংশন ব্যবহার করে করা যেতে পারে।

বিষয়বস্তু প্রদানকারীর অনুমতি

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

যদি কোনো প্রদানকারীর অ্যাপ্লিকেশন কোনো অনুমতি নির্দিষ্ট না করে, তাহলে প্রদানকারী রপ্তানি না করা পর্যন্ত অন্যান্য অ্যাপ্লিকেশনের সরবরাহকারীর ডেটাতে কোনো অ্যাক্সেস থাকবে না। উপরন্তু, প্রদানকারীর অ্যাপ্লিকেশনের উপাদানগুলিতে নির্দিষ্ট অনুমতি নির্বিশেষে সর্বদা সম্পূর্ণ পড়ার এবং লেখার অ্যাক্সেস থাকে।

ব্যবহারকারী অভিধান প্রদানকারীর এটি থেকে ডেটা পুনরুদ্ধার করার জন্য android.permission.READ_USER_DICTIONARY অনুমতি প্রয়োজন। ডেটা সন্নিবেশ করা, আপডেট করা বা মুছে ফেলার জন্য প্রদানকারীর একটি পৃথক android.permission.WRITE_USER_DICTIONARY অনুমতি রয়েছে৷

একটি প্রদানকারীকে অ্যাক্সেস করার জন্য প্রয়োজনীয় অনুমতিগুলি পেতে, একটি অ্যাপ্লিকেশন তাদের ম্যানিফেস্ট ফাইলে একটি <uses-permission> উপাদান দিয়ে অনুরোধ করে। যখন অ্যান্ড্রয়েড প্যাকেজ ম্যানেজার অ্যাপ্লিকেশনটি ইনস্টল করে, তখন ব্যবহারকারীকে অবশ্যই অ্যাপ্লিকেশনটির অনুরোধের সমস্ত অনুমতি অনুমোদন করতে হবে। ব্যবহারকারী তাদের অনুমোদন করলে, প্যাকেজ ম্যানেজার ইনস্টলেশন চালিয়ে যান। ব্যবহারকারী তাদের অনুমোদন না করলে, প্যাকেজ ম্যানেজার ইনস্টলেশন বন্ধ করে দেয়।

নিম্নলিখিত নমুনা <uses-permission> উপাদানটি ব্যবহারকারী অভিধান প্রদানকারীকে পড়ার অ্যাক্সেসের অনুরোধ করে:

<uses-permission android:name="android.permission.READ_USER_DICTIONARY">

প্রদানকারীর অ্যাক্সেসের উপর অনুমতির প্রভাব নিরাপত্তা টিপসে আরও বিস্তারিতভাবে ব্যাখ্যা করা হয়েছে।

তথ্য সন্নিবেশ করান, আপডেট করুন এবং মুছুন

আপনি যেভাবে একটি প্রদানকারীর কাছ থেকে ডেটা পুনরুদ্ধার করেন, একইভাবে আপনি ডেটা পরিবর্তন করতে একটি প্রদানকারী ক্লায়েন্ট এবং প্রদানকারীর ContentProvider মধ্যে মিথস্ক্রিয়া ব্যবহার করেন। আপনি ContentResolver এর একটি পদ্ধতিকে আর্গুমেন্ট সহ কল ​​করেন যা ContentProvider এর সংশ্লিষ্ট পদ্ধতিতে পাস করা হয়। প্রদানকারী এবং প্রদানকারী ক্লায়েন্ট স্বয়ংক্রিয়ভাবে নিরাপত্তা এবং আন্তঃপ্রক্রিয়া যোগাযোগ পরিচালনা করে।

তথ্য সন্নিবেশ করান

একটি প্রদানকারীতে ডেটা সন্নিবেশ করতে, আপনি ContentResolver.insert() পদ্ধতিতে কল করুন। এই পদ্ধতি প্রদানকারীর মধ্যে একটি নতুন সারি সন্নিবেশ করায় এবং সেই সারির জন্য একটি বিষয়বস্তু URI প্রদান করে। নিম্নলিখিত স্নিপেটটি দেখায় কিভাবে ব্যবহারকারী অভিধান প্রদানকারীতে একটি নতুন শব্দ সন্নিবেশ করা যায়:

কোটলিন

// Defines a new Uri object that receives the result of the insertion
lateinit var newUri: Uri
...
// Defines an object to contain the new values to insert
val newValues = ContentValues().apply {
    /*
     * Sets the values of each column and inserts the word. The arguments to the "put"
     * method are "column name" and "value".
     */
    put(UserDictionary.Words.APP_ID, "example.user")
    put(UserDictionary.Words.LOCALE, "en_US")
    put(UserDictionary.Words.WORD, "insert")
    put(UserDictionary.Words.FREQUENCY, "100")

}

newUri = contentResolver.insert(
        UserDictionary.Words.CONTENT_URI,   // The UserDictionary content URI
        newValues                           // The values to insert
)

জাভা

// Defines a new Uri object that receives the result of the insertion
Uri newUri;
...
// Defines an object to contain the new values to insert
ContentValues newValues = new ContentValues();

/*
 * Sets the values of each column and inserts the word. The arguments to the "put"
 * method are "column name" and "value".
 */
newValues.put(UserDictionary.Words.APP_ID, "example.user");
newValues.put(UserDictionary.Words.LOCALE, "en_US");
newValues.put(UserDictionary.Words.WORD, "insert");
newValues.put(UserDictionary.Words.FREQUENCY, "100");

newUri = getContentResolver().insert(
    UserDictionary.Words.CONTENT_URI,   // The UserDictionary content URI
    newValues                           // The values to insert
);

নতুন সারির ডেটা একটি একক ContentValues ​​অবজেক্টে যায়, যা একটি এক-সারির কার্সারের মতো। এই অবজেক্টের কলামগুলির একই ডেটা টাইপ থাকা দরকার নেই, এবং আপনি যদি কোনও মান নির্দিষ্ট করতে না চান তবে আপনি ContentValues.putNull() ব্যবহার করে একটি কলামকে null সেট করতে পারেন।

পূর্ববর্তী স্নিপেটটি _ID কলাম যোগ করে না, কারণ এই কলামটি স্বয়ংক্রিয়ভাবে বজায় থাকে। প্রদানকারী যোগ করা প্রতিটি সারিতে _ID এর একটি অনন্য মান নির্ধারণ করে। সরবরাহকারীরা সাধারণত এই মানটিকে টেবিলের প্রাথমিক কী হিসাবে ব্যবহার করে।

newUri ফিরে আসা বিষয়বস্তু URI নিম্নলিখিত বিন্যাসের সাথে নতুন যোগ করা সারিটিকে চিহ্নিত করে:

content://user_dictionary/words/<id_value>

<id_value> হল নতুন সারির জন্য _ID এর বিষয়বস্তু। বেশিরভাগ প্রদানকারী স্বয়ংক্রিয়ভাবে এই ধরনের বিষয়বস্তু URI সনাক্ত করতে পারে এবং তারপর সেই নির্দিষ্ট সারিতে অনুরোধকৃত অপারেশন সম্পাদন করতে পারে।

ফিরে আসা Uri থেকে _ID এর মান পেতে, ContentUris.parseId() কল করুন।

ডেটা আপডেট করুন

একটি সারি আপডেট করতে, আপনি আপডেট করা মান সহ একটি ContentValues অবজেক্ট ব্যবহার করেন, ঠিক যেমন আপনি একটি সন্নিবেশ এবং নির্বাচনের মানদণ্ডের সাথে করেন, যেমন আপনি একটি প্রশ্নের সাথে করেন। আপনি যে ক্লায়েন্ট পদ্ধতিটি ব্যবহার করেন তা হল ContentResolver.update() । আপনি যে কলাম আপডেট করছেন তার জন্য আপনাকে শুধুমাত্র ContentValues ​​অবজেক্টে মান যোগ করতে হবে। আপনি যদি একটি কলামের বিষয়বস্তু সাফ করতে চান, তাহলে মানটিকে null এ সেট করুন।

নিম্নলিখিত স্নিপেটটি সমস্ত সারি পরিবর্তন করে যার লোকেলের ভাষা "en" আছে একটি null এর একটি লোকেলে। রিটার্ন মান হল আপডেট করা সারির সংখ্যা।

কোটলিন

// Defines an object to contain the updated values
val updateValues = ContentValues().apply {
    /*
     * Sets the updated value and updates the selected words.
     */
    putNull(UserDictionary.Words.LOCALE)
}

// Defines selection criteria for the rows you want to update
val selectionClause: String = UserDictionary.Words.LOCALE + "LIKE ?"
val selectionArgs: Array<String> = arrayOf("en_%")

// Defines a variable to contain the number of updated rows
var rowsUpdated: Int = 0
...
rowsUpdated = contentResolver.update(
        UserDictionary.Words.CONTENT_URI,  // The UserDictionary content URI
        updateValues,                      // The columns to update
        selectionClause,                   // The column to select on
        selectionArgs                      // The value to compare to
)

জাভা

// Defines an object to contain the updated values
ContentValues updateValues = new ContentValues();

// Defines selection criteria for the rows you want to update
String selectionClause = UserDictionary.Words.LOCALE +  " LIKE ?";
String[] selectionArgs = {"en_%"};

// Defines a variable to contain the number of updated rows
int rowsUpdated = 0;
...
/*
 * Sets the updated value and updates the selected words.
 */
updateValues.putNull(UserDictionary.Words.LOCALE);

rowsUpdated = getContentResolver().update(
    UserDictionary.Words.CONTENT_URI,  // The UserDictionary content URI
    updateValues,                      // The columns to update
    selectionClause,                   // The column to select on
    selectionArgs                      // The value to compare to
);

আপনি যখন ContentResolver.update() কল করেন তখন ব্যবহারকারীর ইনপুট স্যানিটাইজ করুন। এই সম্পর্কে আরও জানতে, ক্ষতিকারক ইনপুট থেকে রক্ষা করুন বিভাগটি পড়ুন।

ডেটা মুছুন

সারি মুছে ফেলা সারি ডেটা পুনরুদ্ধারের অনুরূপ। আপনি যে সারিগুলি মুছতে চান তার জন্য নির্বাচনের মানদণ্ড নির্দিষ্ট করুন এবং ক্লায়েন্ট পদ্ধতিটি মুছে ফেলা সারির সংখ্যা প্রদান করে। নিম্নলিখিত স্নিপেটটি সারিগুলি মুছে দেয় যার অ্যাপ আইডি "user" সাথে মেলে। পদ্ধতিটি মুছে ফেলা সারির সংখ্যা প্রদান করে।

কোটলিন

// Defines selection criteria for the rows you want to delete
val selectionClause = "${UserDictionary.Words.APP_ID} LIKE ?"
val selectionArgs: Array<String> = arrayOf("user")

// Defines a variable to contain the number of rows deleted
var rowsDeleted: Int = 0
...
// Deletes the words that match the selection criteria
rowsDeleted = contentResolver.delete(
        UserDictionary.Words.CONTENT_URI,  // The UserDictionary content URI
        selectionClause,                   // The column to select on
        selectionArgs                      // The value to compare to
)

জাভা

// Defines selection criteria for the rows you want to delete
String selectionClause = UserDictionary.Words.APP_ID + " LIKE ?";
String[] selectionArgs = {"user"};

// Defines a variable to contain the number of rows deleted
int rowsDeleted = 0;
...
// Deletes the words that match the selection criteria
rowsDeleted = getContentResolver().delete(
    UserDictionary.Words.CONTENT_URI,  // The UserDictionary content URI
    selectionClause,                   // The column to select on
    selectionArgs                      // The value to compare to
);

আপনি যখন ContentResolver.delete() কল করেন তখন ব্যবহারকারীর ইনপুট স্যানিটাইজ করুন। এই সম্পর্কে আরও জানতে, ক্ষতিকারক ইনপুট থেকে রক্ষা করুন বিভাগটি পড়ুন।

প্রদানকারী ডেটা প্রকার

বিষয়বস্তু প্রদানকারীরা বিভিন্ন ধরনের ডেটা অফার করতে পারে। ব্যবহারকারী অভিধান প্রদানকারী শুধুমাত্র পাঠ্য অফার করে, কিন্তু প্রদানকারীরা নিম্নলিখিত বিন্যাসগুলিও অফার করতে পারে:

  • পূর্ণসংখ্যা
  • দীর্ঘ পূর্ণসংখ্যা (দীর্ঘ)
  • ভাসমান বিন্দু
  • দীর্ঘ ভাসমান বিন্দু (ডবল)

আরেকটি ডেটা টাইপ যা প্রদানকারীরা প্রায়শই ব্যবহার করে তা হল একটি বাইনারি লার্জ অবজেক্ট (BLOB) যা একটি 64 KB বাইট অ্যারে হিসাবে প্রয়োগ করা হয়। আপনি Cursor ক্লাস "পান" পদ্ধতিগুলি দেখে উপলব্ধ ডেটা প্রকারগুলি দেখতে পারেন।

একটি প্রদানকারীর প্রতিটি কলামের জন্য ডেটা টাইপ সাধারণত তার ডকুমেন্টেশনে তালিকাভুক্ত করা হয়। ব্যবহারকারী অভিধান প্রদানকারীর জন্য ডেটা প্রকারগুলি তার চুক্তি শ্রেণীর, UserDictionary.Words এর জন্য রেফারেন্স ডকুমেন্টেশনে তালিকাভুক্ত করা হয়েছে। কন্ট্রাক্ট ক্লাস কন্ট্রাক্ট ক্লাস বিভাগে বর্ণনা করা হয়েছে। এছাড়াও আপনি Cursor.getType() কল করে ডেটা টাইপ নির্ধারণ করতে পারেন।

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

উদাহরণস্বরূপ, পরিচিতি প্রদানকারীর ContactsContract.Data টেবিলটি প্রতিটি সারিতে সংরক্ষিত যোগাযোগের ডেটার ধরন লেবেল করতে MIME প্রকারগুলি ব্যবহার করে৷ একটি বিষয়বস্তু URI-এর সাথে সঙ্গতিপূর্ণ MIME প্রকার পেতে, ContentResolver.getType() এ কল করুন।

MIME টাইপ রেফারেন্স বিভাগটি স্ট্যান্ডার্ড এবং কাস্টম MIME ধরনের উভয়ের সিনট্যাক্স বর্ণনা করে।

প্রদানকারী অ্যাক্সেসের বিকল্প ফর্ম

প্রদানকারী অ্যাক্সেসের তিনটি বিকল্প ফর্ম অ্যাপ্লিকেশন বিকাশে গুরুত্বপূর্ণ:

  • ব্যাচ অ্যাক্সেস : আপনি ContentProviderOperation ক্লাসের পদ্ধতিগুলির সাথে অ্যাক্সেস কলগুলির একটি ব্যাচ তৈরি করতে পারেন এবং তারপরে ContentResolver.applyBatch() দিয়ে প্রয়োগ করতে পারেন।
  • অ্যাসিঙ্ক্রোনাস প্রশ্ন: একটি পৃথক থ্রেডে প্রশ্নগুলি করুন। আপনি একটি CursorLoader অবজেক্ট ব্যবহার করতে পারেন। লোডার গাইডের উদাহরণগুলি কীভাবে এটি করতে হয় তা প্রদর্শন করে।
  • অভিপ্রায় ব্যবহার করে ডেটা অ্যাক্সেস : যদিও আপনি সরাসরি কোনও প্রদানকারীর কাছে একটি অভিপ্রায় পাঠাতে পারেন না, আপনি প্রদানকারীর অ্যাপ্লিকেশনে একটি অভিপ্রায় পাঠাতে পারেন, যা সাধারণত প্রদানকারীর ডেটা পরিবর্তন করার জন্য সর্বোত্তমভাবে সজ্জিত।

ইন্টেন্ট ব্যবহার করে ব্যাচ অ্যাক্সেস এবং পরিবর্তন নিম্নলিখিত বিভাগে বর্ণিত হয়েছে।

ব্যাচ অ্যাক্সেস

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

ব্যাচ মোডে একটি প্রদানকারীকে অ্যাক্সেস করতে, ContentProviderOperation অবজেক্টের একটি অ্যারে তৈরি করুন এবং তারপর ContentResolver.applyBatch() সহ একটি সামগ্রী প্রদানকারীর কাছে প্রেরণ করুন। আপনি একটি নির্দিষ্ট বিষয়বস্তু URI-এর পরিবর্তে এই পদ্ধতিতে সামগ্রী প্রদানকারীর কর্তৃপক্ষকে পাস করেন৷

এটি অ্যারের প্রতিটি ContentProviderOperation অবজেক্টকে একটি ভিন্ন টেবিলের বিরুদ্ধে কাজ করতে দেয়। ContentResolver.applyBatch() এ কল করা ফলাফলের একটি অ্যারে প্রদান করে।

ContactsContract.RawContacts কন্ট্রাক্ট ক্লাসের বিবরণে একটি কোড স্নিপেট রয়েছে যা ব্যাচ সন্নিবেশ প্রদর্শন করে।

উদ্দেশ্য ব্যবহার করে ডেটা অ্যাক্সেস

উদ্দেশ্য একটি বিষয়বস্তু প্রদানকারীকে পরোক্ষ অ্যাক্সেস প্রদান করতে পারে। আপনার অ্যাপ্লিকেশানের অ্যাক্সেসের অনুমতি না থাকলেও অনুমতি আছে এমন কোনও অ্যাপ্লিকেশান থেকে ফলাফলের অভিপ্রায় ফিরে পেয়ে বা অনুমতি আছে এমন কোনও অ্যাপ্লিকেশান সক্রিয় করে এবং ব্যবহারকারীকে এতে কাজ করার অনুমতি দিয়ে আপনি ব্যবহারকারীকে কোনও প্রদানকারীর ডেটা অ্যাক্সেস করতে দিতে পারেন৷

অস্থায়ী অনুমতির সাথে অ্যাক্সেস পান

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

দ্রষ্টব্য: এই পতাকাগুলি সেই প্রদানকারীকে সাধারণ পাঠ বা লেখার অ্যাক্সেস দেয় না যার কর্তৃত্ব বিষয়বস্তু URI-তে রয়েছে৷ অ্যাক্সেস শুধুমাত্র URI নিজেই জন্য.

আপনি যখন অন্য অ্যাপে কন্টেন্ট ইউআরআই পাঠান, তখন এই ফ্ল্যাগগুলির মধ্যে অন্তত একটি অন্তর্ভুক্ত করুন। ফ্ল্যাগগুলি যে কোনও অ্যাপকে নিম্নলিখিত ক্ষমতাগুলি প্রদান করে যা একটি অভিপ্রায় গ্রহণ করে এবং লক্ষ্য করে Android 11 (API স্তর 30) বা উচ্চতর:

  • উদ্দেশ্য অন্তর্ভুক্ত পতাকার উপর নির্ভর করে, বিষয়বস্তু URI প্রতিনিধিত্ব করে এমন ডেটা থেকে পড়ুন বা লিখুন।
  • ইউআরআই কর্তৃপক্ষের সাথে মেলে এমন সামগ্রী প্রদানকারী ধারণকারী অ্যাপে প্যাকেজ দৃশ্যমানতা লাভ করুন। যে অ্যাপটি অভিপ্রায় পাঠায় এবং যে অ্যাপটিতে বিষয়বস্তু প্রদানকারী রয়েছে সেটি দুটি ভিন্ন অ্যাপ হতে পারে।

একটি প্রদানকারী <provider> উপাদানের android:grantUriPermissions বৈশিষ্ট্যের পাশাপাশি <provider> উপাদানের <grant-uri-permission> চাইল্ড এলিমেন্ট ব্যবহার করে তার ম্যানিফেস্টে কন্টেন্ট URI-এর জন্য URI অনুমতি সংজ্ঞায়িত করে। URI পারমিশন মেকানিজম অ্যান্ড্রয়েড গাইডে আরও বিস্তারিতভাবে ব্যাখ্যা করা হয়েছে।

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

  1. আপনার আবেদনে, startActivityForResult() পদ্ধতিটি ব্যবহার করে ACTION_PICK এবং "পরিচিতি" MIME প্রকার CONTENT_ITEM_TYPE সহ একটি অভিপ্রায় পাঠান।
  2. যেহেতু এই অভিপ্রায়টি পিপল অ্যাপের "নির্বাচন" কার্যকলাপের জন্য অভিপ্রায় ফিল্টারের সাথে মেলে, কার্যকলাপটি অগ্রভাগে আসে৷
  3. নির্বাচন কার্যকলাপে, ব্যবহারকারী আপডেট করার জন্য একটি পরিচিতি নির্বাচন করে। যখন এটি ঘটবে, নির্বাচন কার্যকলাপ আপনার আবেদন ফেরত দিতে একটি অভিপ্রায় সেট আপ করতে setResult(resultcode, intent) কল করে। অভিপ্রায়টিতে ব্যবহারকারীর নির্বাচিত যোগাযোগের সামগ্রীর URI এবং "অতিরিক্ত" ফ্ল্যাগ FLAG_GRANT_READ_URI_PERMISSION রয়েছে৷ এই ফ্ল্যাগগুলি আপনার অ্যাপকে URI-এর অনুমতি দেয় কন্টেন্ট URI দ্বারা নির্দেশিত পরিচিতির ডেটা পড়ার জন্য। নির্বাচন কার্যকলাপ তারপর finish() কল করে আপনার অ্যাপ্লিকেশনে নিয়ন্ত্রণ ফিরিয়ে আনতে।
  4. আপনার কার্যকলাপ ফোরগ্রাউন্ডে ফিরে আসে, এবং সিস্টেমটি আপনার কার্যকলাপের onActivityResult() পদ্ধতিতে কল করে। এই পদ্ধতিটি পিপল অ্যাপে সিলেকশন অ্যাক্টিভিটি দ্বারা তৈরি ফলাফলের উদ্দেশ্য গ্রহণ করে।
  5. ফলাফলের অভিপ্রায় থেকে বিষয়বস্তু URI সহ, আপনি পরিচিতি প্রদানকারী থেকে পরিচিতির ডেটা পড়তে পারেন, যদিও আপনি আপনার ম্যানিফেস্টে প্রদানকারীর কাছে স্থায়ীভাবে পড়ার অ্যাক্সেসের অনুমতির অনুরোধ করেননি৷ তারপর আপনি পরিচিতির জন্মদিনের তথ্য বা ইমেল ঠিকানা পেতে পারেন এবং তারপর ই-গ্রিটিং পাঠাতে পারেন।

অন্য অ্যাপ্লিকেশন ব্যবহার করুন

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

উদাহরণস্বরূপ, ক্যালেন্ডার অ্যাপ্লিকেশনটি একটি ACTION_INSERT অভিপ্রায় গ্রহণ করে যা আপনাকে অ্যাপ্লিকেশনটির সন্নিবেশ UI সক্রিয় করতে দেয়৷ আপনি এই অভিপ্রায়ে "অতিরিক্ত" ডেটা পাস করতে পারেন, যা অ্যাপ্লিকেশনটি UI-কে প্রাক-পপুলেট করতে ব্যবহার করে। কারণ পুনরাবৃত্ত ইভেন্টগুলির একটি জটিল সিনট্যাক্স থাকে, ক্যালেন্ডার প্রদানকারীতে ইভেন্টগুলি সন্নিবেশ করার পছন্দের উপায় হল একটি ACTION_INSERT দিয়ে ক্যালেন্ডার অ্যাপ সক্রিয় করা এবং তারপরে ব্যবহারকারীকে সেখানে ইভেন্টটি সন্নিবেশ করতে দেওয়া৷

একটি সহায়ক অ্যাপ ব্যবহার করে ডেটা প্রদর্শন করুন

আপনার অ্যাপ্লিকেশানের অ্যাক্সেসের অনুমতি থাকলে , আপনি এখনও অন্য অ্যাপ্লিকেশানে ডেটা প্রদর্শনের জন্য একটি উদ্দেশ্য ব্যবহার করতে পারেন৷ উদাহরণস্বরূপ, ক্যালেন্ডার অ্যাপ্লিকেশন একটি ACTION_VIEW উদ্দেশ্য গ্রহণ করে যা একটি নির্দিষ্ট তারিখ বা ইভেন্ট প্রদর্শন করে। এটি আপনাকে আপনার নিজস্ব UI তৈরি না করেই ক্যালেন্ডারের তথ্য প্রদর্শন করতে দেয়৷ এই বৈশিষ্ট্য সম্পর্কে আরও জানতে, ক্যালেন্ডার প্রদানকারীর ওভারভিউ দেখুন।

আপনি যে অ্যাপ্লিকেশনটিতে অভিপ্রায় পাঠান সেটি প্রদানকারীর সাথে যুক্ত অ্যাপ্লিকেশন হতে হবে না। উদাহরণস্বরূপ, আপনি পরিচিতি প্রদানকারীর কাছ থেকে একটি পরিচিতি পুনরুদ্ধার করতে পারেন, তারপর একটি ACTION_VIEW অভিপ্রায় পাঠাতে পারেন যার মধ্যে যোগাযোগের চিত্রের জন্য সামগ্রীর URI একটি চিত্র দর্শককে পাঠান৷

কন্ট্রাক্ট ক্লাস

একটি চুক্তি শ্রেণী ধ্রুবকগুলিকে সংজ্ঞায়িত করে যা অ্যাপ্লিকেশনগুলিকে সামগ্রীর URI, কলামের নাম, অভিপ্রায় ক্রিয়া এবং একটি সামগ্রী প্রদানকারীর অন্যান্য বৈশিষ্ট্যগুলির সাথে কাজ করতে সহায়তা করে৷ চুক্তির ক্লাসগুলি কোনও প্রদানকারীর সাথে স্বয়ংক্রিয়ভাবে অন্তর্ভুক্ত হয় না। প্রদানকারীর বিকাশকারীকে সেগুলি সংজ্ঞায়িত করতে হবে এবং তারপরে সেগুলি অন্যান্য বিকাশকারীদের কাছে উপলব্ধ করতে হবে৷ অ্যান্ড্রয়েড প্ল্যাটফর্মের সাথে অন্তর্ভুক্ত অনেক প্রদানকারীর android.provider প্যাকেজে সংশ্লিষ্ট চুক্তির ক্লাস রয়েছে।

উদাহরণ স্বরূপ, ইউজার ডিকশনারি প্রদানকারীর একটি কন্ট্রাক্ট ক্লাস UserDictionary রয়েছে যাতে কন্টেন্ট URI এবং কলামের নাম ধ্রুবক থাকে। Words টেবিলের জন্য বিষয়বস্তু URI ধ্রুবক UserDictionary.Words.CONTENT_URI এ সংজ্ঞায়িত করা হয়েছে। UserDictionary.Words ক্লাসে কলামের নাম ধ্রুবকও রয়েছে, যা এই নির্দেশিকায় উদাহরণ স্নিপেটগুলিতে ব্যবহৃত হয়। উদাহরণস্বরূপ, একটি ক্যোয়ারী প্রজেকশন নিম্নলিখিত মত সংজ্ঞায়িত করা যেতে পারে:

কোটলিন

val projection : Array<String> = arrayOf(
        UserDictionary.Words._ID,
        UserDictionary.Words.WORD,
        UserDictionary.Words.LOCALE
)

জাভা

String[] projection =
{
    UserDictionary.Words._ID,
    UserDictionary.Words.WORD,
    UserDictionary.Words.LOCALE
};

আরেকটি চুক্তির শ্রেণী হল পরিচিতি প্রদানকারীর জন্য ContactsContract । এই শ্রেণীর জন্য রেফারেন্স ডকুমেন্টেশন উদাহরণ কোড স্নিপেট অন্তর্ভুক্ত. এর একটি সাবক্লাস, ContactsContract.Intents.Insert , হল একটি চুক্তির শ্রেণী যাতে উদ্দেশ্য এবং অভিপ্রায় ডেটার জন্য ধ্রুবক থাকে।

MIME প্রকার রেফারেন্স

বিষয়বস্তু প্রদানকারীরা স্ট্যান্ডার্ড MIME মিডিয়া প্রকার, কাস্টম MIME টাইপ স্ট্রিং বা উভয়ই ফেরত দিতে পারে।

MIME প্রকারের নিম্নলিখিত বিন্যাস রয়েছে:

type/subtype

উদাহরণস্বরূপ, সুপরিচিত MIME টাইপ text/html text টাইপ এবং html সাবটাইপ রয়েছে। যদি প্রদানকারী একটি URI-এর জন্য এই ধরনের রিটার্ন করে, তাহলে এর মানে হল যে URI ব্যবহার করে একটি ক্যোয়ারী HTML ট্যাগ সম্বলিত টেক্সট প্রদান করে।

কাস্টম MIME প্রকারের স্ট্রিং, যাকে বিক্রেতা-নির্দিষ্ট MIME প্রকারও বলা হয়, এর আরও জটিল type এবং subtype মান রয়েছে। একাধিক সারির জন্য, প্রকার মান সর্বদা নিম্নরূপ:

vnd.android.cursor.dir

একটি একক সারির জন্য, প্রকার মান সর্বদা নিম্নরূপ:

vnd.android.cursor.item

subtype প্রদানকারী-নির্দিষ্ট। অ্যান্ড্রয়েড বিল্ট-ইন প্রদানকারীদের সাধারণত একটি সাধারণ সাবটাইপ থাকে। উদাহরণস্বরূপ, যখন পরিচিতি অ্যাপ্লিকেশন একটি টেলিফোন নম্বরের জন্য একটি সারি তৈরি করে, তখন এটি সারিতে নিম্নলিখিত MIME প্রকার সেট করে:

vnd.android.cursor.item/phone_v2

সাব-টাইপ মান হল phone_v2

অন্যান্য প্রদানকারী বিকাশকারীরা প্রদানকারীর কর্তৃত্ব এবং টেবিলের নামের উপর ভিত্তি করে তাদের নিজস্ব উপপ্রকারের প্যাটার্ন তৈরি করতে পারে। উদাহরণস্বরূপ, ট্রেনের সময়সূচী রয়েছে এমন একটি প্রদানকারীর কথা বিবেচনা করুন। প্রদানকারীর কর্তৃত্ব হল com.example.trains , এবং এতে লাইন1, লাইন2 এবং লাইন3 টেবিল রয়েছে। সারণি লাইন 1-এর জন্য নিম্নলিখিত বিষয়বস্তুর URI-এর প্রতিক্রিয়ায়:

content://com.example.trains/Line1

প্রদানকারী নিম্নলিখিত MIME প্রকার প্রদান করে:

vnd.android.cursor.dir/vnd.example.line1

সারণি লাইন 2-এ সারি 5-এর জন্য নিম্নলিখিত বিষয়বস্তুর URI-এর প্রতিক্রিয়ায়:

content://com.example.trains/Line2/5

প্রদানকারী নিম্নলিখিত MIME প্রকার প্রদান করে:

vnd.android.cursor.item/vnd.example.line2

বেশিরভাগ বিষয়বস্তু প্রদানকারীরা তাদের ব্যবহার করা MIME প্রকারের জন্য চুক্তি শ্রেণীর ধ্রুবক সংজ্ঞায়িত করে। পরিচিতি প্রদানকারী চুক্তি শ্রেণী ContactsContract.RawContacts , উদাহরণস্বরূপ, একটি একক কাঁচা পরিচিতি সারির MIME প্রকারের জন্য ধ্রুবক CONTENT_ITEM_TYPE সংজ্ঞায়িত করে৷

একক সারিগুলির জন্য সামগ্রী URIগুলি বিষয়বস্তু URIs বিভাগে বর্ণিত হয়েছে৷