অ্যান্ড্রয়েড কপি ও পেস্ট করার জন্য একটি শক্তিশালী ক্লিপবোর্ড-ভিত্তিক ফ্রেমওয়ার্ক প্রদান করে। এটি টেক্সট স্ট্রিং, জটিল ডেটা স্ট্রাকচার, টেক্সট ও বাইনারি স্ট্রিম ডেটা এবং অ্যাপ্লিকেশন অ্যাসেট সহ সহজ ও জটিল ডেটা টাইপ সমর্থন করে। সহজ টেক্সট ডেটা সরাসরি ক্লিপবোর্ডে সংরক্ষিত হয়, অন্যদিকে জটিল ডেটা একটি রেফারেন্স হিসেবে সংরক্ষিত হয়, যা পেস্টকারী অ্যাপ্লিকেশনটি একটি কন্টেন্ট প্রোভাইডারের মাধ্যমে সমাধান করে। কপি ও পেস্ট একটি অ্যাপ্লিকেশনের মধ্যে এবং ফ্রেমওয়ার্কটি বাস্তবায়নকারী অ্যাপ্লিকেশনগুলোর মধ্যে উভয় ক্ষেত্রেই কাজ করে।
যেহেতু ফ্রেমওয়ার্কের একটি অংশ কন্টেন্ট প্রোভাইডার ব্যবহার করে, তাই এই ডকুমেন্টটি ধরে নিচ্ছে যে অ্যান্ড্রয়েড কন্টেন্ট প্রোভাইডার এপিআই (Android Content Provider API) সম্পর্কে আপনার কিছুটা ধারণা আছে, যা 'কন্টেন্ট প্রোভাইডারস' (Content providers) অংশে বর্ণনা করা হয়েছে।
ক্লিপবোর্ডে কন্টেন্ট কপি করার সময় ব্যবহারকারীরা ফিডব্যাক আশা করেন, তাই কপি ও পেস্টের ফ্রেমওয়ার্কের পাশাপাশি, অ্যান্ড্রয়েড ১৩ (এপিআই লেভেল ৩৩) এবং এর পরবর্তী সংস্করণগুলোতে কপি করার সময় অ্যান্ড্রয়েড ব্যবহারকারীদের একটি ডিফল্ট ইউআই দেখায়। এই ফিচারের কারণে, ডুপ্লিকেট নোটিফিকেশন আসার ঝুঁকি থাকে। আপনি ‘ডুপ্লিকেট নোটিফিকেশন এড়িয়ে চলুন’ বিভাগে এই বিশেষ পরিস্থিতিটি সম্পর্কে আরও জানতে পারবেন।

Android 12L (API লেভেল 32) এবং এর নিচের সংস্করণগুলোতে কপি করার সময় ব্যবহারকারীদের ম্যানুয়ালি ফিডব্যাক দিন। এ বিষয়ে সুপারিশের জন্য এই ডকুমেন্টটি দেখুন।
ক্লিপবোর্ড ফ্রেমওয়ার্ক
যখন আপনি ক্লিপবোর্ড ফ্রেমওয়ার্ক ব্যবহার করেন, তখন একটি ক্লিপ অবজেক্টে ডেটা রাখুন এবং তারপর সেই ক্লিপ অবজেক্টটি সিস্টেম-ব্যাপী ক্লিপবোর্ডে রাখুন। ক্লিপ অবজেক্টটি তিনটি রূপের যেকোনো একটি নিতে পারে:
- পাঠ্য
- একটি টেক্সট স্ট্রিং। স্ট্রিংটি সরাসরি ক্লিপ অবজেক্টে রাখুন, যা আপনি পরে ক্লিপবোর্ডে রাখবেন। স্ট্রিংটি পেস্ট করতে, ক্লিপবোর্ড থেকে ক্লিপ অবজেক্টটি নিন এবং স্ট্রিংটি আপনার অ্যাপ্লিকেশনের স্টোরেজে কপি করুন।
- ইউআরআই
- যেকোনো ধরনের URI-কে প্রতিনিধিত্বকারী একটি
Uriঅবজেক্ট। এটি মূলত একটি কন্টেন্ট প্রোভাইডার থেকে জটিল ডেটা কপি করার জন্য ব্যবহৃত হয়। ডেটা কপি করতে, একটিUriঅবজেক্টকে একটি clip অবজেক্টের মধ্যে রাখুন এবং clip অবজেক্টটিকে ক্লিপবোর্ডে রাখুন। ডেটা পেস্ট করতে, clip অবজেক্টটি নিন,Uriঅবজেক্টটি নিন, এটিকে একটি ডেটা সোর্সে (যেমন একটি কন্টেন্ট প্রোভাইডার) রিজলভ করুন এবং সোর্স থেকে ডেটাটি আপনার অ্যাপ্লিকেশনের স্টোরেজে কপি করুন। - উদ্দেশ্য
- একটি
Intent)। এটি অ্যাপ্লিকেশন শর্টকাট কপি করতে সহায়তা করে। ডেটা কপি করার জন্য, একটিIntentতৈরি করুন, সেটিকে একটি ক্লিপ অবজেক্টের মধ্যে রাখুন এবং ক্লিপ অবজেক্টটি ক্লিপবোর্ডে রাখুন। ডেটা পেস্ট করার জন্য, ক্লিপ অবজেক্টটি নিন এবং তারপরIntentঅবজেক্টটি আপনার অ্যাপ্লিকেশনের মেমোরি এরিয়াতে কপি করুন।
ক্লিপবোর্ডে একবারে কেবল একটি ক্লিপ অবজেক্ট রাখা যায়। যখন কোনো অ্যাপ্লিকেশন ক্লিপবোর্ডে একটি ক্লিপ অবজেক্ট রাখে, তখন পূর্ববর্তী ক্লিপ অবজেক্টটি অদৃশ্য হয়ে যায়।
আপনি যদি ব্যবহারকারীদের আপনার অ্যাপ্লিকেশনে ডেটা পেস্ট করার সুযোগ দিতে চান, তবে আপনাকে সব ধরনের ডেটা পরিচালনা করতে হবে না। ব্যবহারকারীদের পেস্ট করার বিকল্প দেওয়ার আগে আপনি ক্লিপবোর্ডে থাকা ডেটা পরীক্ষা করে দেখতে পারেন। একটি নির্দিষ্ট ডেটা ফর্ম থাকার পাশাপাশি, ক্লিপ অবজেক্টে মেটাডেটাও থাকে যা আপনাকে বলে দেয় কোন MIME টাইপগুলো উপলব্ধ আছে। এই মেটাডেটা আপনাকে সিদ্ধান্ত নিতে সাহায্য করে যে আপনার অ্যাপ্লিকেশনটি ক্লিপবোর্ডের ডেটা দিয়ে কোনো দরকারি কাজ করতে পারবে কি না। উদাহরণস্বরূপ, যদি আপনার এমন একটি অ্যাপ্লিকেশন থাকে যা প্রধানত টেক্সট নিয়ে কাজ করে, তবে আপনি URI বা ইন্টেন্ট ধারণকারী ক্লিপ অবজেক্টগুলোকে উপেক্ষা করতে চাইতে পারেন।
আপনি হয়তো ক্লিপবোর্ডে থাকা ডেটার ধরন নির্বিশেষে ব্যবহারকারীদের টেক্সট পেস্ট করার সুযোগ দিতে চাইতে পারেন। এটি করার জন্য, ক্লিপবোর্ডের ডেটাকে টেক্সট আকারে রূপান্তর করুন এবং তারপর এই টেক্সটটি পেস্ট করুন। এই বিষয়টি ‘ক্লিপবোর্ডকে টেক্সটে রূপান্তর’ অংশে বর্ণনা করা হয়েছে।
ক্লিপবোর্ড ক্লাস
এই অংশে ক্লিপবোর্ড ফ্রেমওয়ার্ক দ্বারা ব্যবহৃত ক্লাসগুলো বর্ণনা করা হয়েছে।
ক্লিপবোর্ড ম্যানেজার
অ্যান্ড্রয়েড সিস্টেম ক্লিপবোর্ডটি গ্লোবাল ClipboardManager ক্লাস দ্বারা প্রতিনিধিত্ব করা হয়। সরাসরি এই ক্লাসটি ইনস্ট্যানশিয়েট করবেন না। এর পরিবর্তে, getSystemService(CLIPBOARD_SERVICE) কল করে এটির একটি রেফারেন্স নিন।
ClipData, ClipData.Item, এবং ClipDescription
ক্লিপবোর্ডে ডেটা যোগ করতে, একটি ClipData অবজেক্ট তৈরি করুন যাতে ডেটার বিবরণ এবং মূল ডেটাটি থাকে। ক্লিপবোর্ডে একবারে একটি ClipData ধারণ করা যায়। একটি ClipData একটি ClipDescription অবজেক্ট এবং এক বা একাধিক ClipData.Item অবজেক্ট থাকে।
একটি ClipDescription অবজেক্টে ক্লিপটি সম্পর্কে মেটাডেটা থাকে। বিশেষ করে, এতে ক্লিপের ডেটার জন্য উপলব্ধ MIME টাইপগুলোর একটি অ্যারে থাকে। এছাড়াও, Android 12 (API লেভেল 31) এবং তার পরবর্তী সংস্করণগুলোতে, মেটাডেটাতে এই তথ্যও অন্তর্ভুক্ত থাকে যে অবজেক্টটিতে স্টাইলাইজড টেক্সট আছে কিনা এবং অবজেক্টের টেক্সটের ধরন কী। যখন আপনি ক্লিপবোর্ডে একটি ক্লিপ রাখেন, তখন এই তথ্য পেস্ট করার অ্যাপ্লিকেশনগুলোর কাছে উপলব্ধ হয়, যেগুলো ক্লিপের ডেটা হ্যান্ডেল করতে পারবে কিনা তা পরীক্ষা করে দেখতে পারে।
একটি ClipData.Item অবজেক্টে টেক্সট, URI, বা ইনটেন্ট ডেটা থাকে:
- পাঠ্য
- একটি
CharSequence। - ইউআরআই
- একটি
Uri। এতে সাধারণত একটি কন্টেন্ট প্রোভাইডার URI থাকে, যদিও যেকোনো URI-ই অনুমোদিত। যে অ্যাপ্লিকেশনটি ডেটা সরবরাহ করে, সেটি URI-টি ক্লিপবোর্ডে রাখে। যে অ্যাপ্লিকেশনগুলো ডেটা পেস্ট করতে চায়, তারা ক্লিপবোর্ড থেকে URI-টি নিয়ে কন্টেন্ট প্রোভাইডার বা অন্য কোনো ডেটা সোর্স অ্যাক্সেস করতে এবং ডেটা পুনরুদ্ধার করতে এটি ব্যবহার করে। - উদ্দেশ্য
-
Intent। এই ডেটা টাইপটি আপনাকে ক্লিপবোর্ডে একটি অ্যাপ্লিকেশন শর্টকাট কপি করতে দেয়। ব্যবহারকারীরা পরবর্তীতে ব্যবহারের জন্য শর্টকাটটি তাদের অ্যাপ্লিকেশনগুলিতে পেস্ট করতে পারেন।
আপনি একটি ক্লিপে একাধিক ClipData.Item অবজেক্ট যোগ করতে পারেন। এটি ব্যবহারকারীদের একাধিক নির্বাচিত অংশকে একটি একক ক্লিপ হিসাবে কপি এবং পেস্ট করার সুযোগ দেয়। উদাহরণস্বরূপ, যদি আপনার একটি লিস্ট উইজেট থাকে যা ব্যবহারকারীকে একবারে একাধিক আইটেম নির্বাচন করতে দেয়, তবে আপনি সমস্ত আইটেম একসাথে ক্লিপবোর্ডে কপি করতে পারেন। এটি করার জন্য, প্রতিটি লিস্ট আইটেমের জন্য একটি পৃথক ClipData.Item তৈরি করুন এবং তারপর ClipData.Item অবজেক্টগুলিকে ClipData অবজেক্টে যোগ করুন।
ক্লিপডেটা সুবিধাজনক পদ্ধতি
ClipData ক্লাসটি একটিমাত্র ClipData.Item অবজেক্ট এবং একটি সাধারণ ClipDescription অবজেক্ট সহ একটি ClipData অবজেক্ট তৈরি করার জন্য স্ট্যাটিক সুবিধাজনক মেথড প্রদান করে:
-
newPlainText(label, text) - একটি
ClipDataঅবজেক্ট রিটার্ন করে, যার একমাত্রClipData.Itemঅবজেক্টটিতে একটি টেক্সট স্ট্রিং থাকে।ClipDescriptionঅবজেক্টটির লেবেলlabelহিসেবে সেট করা থাকে।ClipDescriptionএর একমাত্র MIME টাইপ হলোMIMETYPE_TEXT_PLAIN।একটি টেক্সট স্ট্রিং থেকে ক্লিপ তৈরি করতে
newPlainText()ব্যবহার করুন। -
newUri(resolver, label, URI) - একটি
ClipDataঅবজেক্ট রিটার্ন করে, যার একমাত্রClipData.Itemঅবজেক্টটিতে একটি URI থাকে।ClipDescriptionঅবজেক্টটির লেবেলlabelহিসেবে সেট করা হয়। যদি URI-টি একটি কন্টেন্ট URI হয়—অর্থাৎ, যদিUri.getScheme()content:` রিটার্ন করে—তাহলে মেথডটিresolverএ দেওয়া `ContentResolverঅবজেক্ট ব্যবহার করে কন্টেন্ট প্রোভাইডার থেকে উপলব্ধ MIME টাইপগুলো সংগ্রহ করে। এরপর এটি সেগুলোকেClipDescriptionএ সংরক্ষণ করে। যে URIcontent:` URI নয়, তার ক্ষেত্রে মেথডটি MIME টাইপকেMIMETYPE_TEXT_URILISTহিসেবে সেট করে।একটি URI থেকে—বিশেষ করে
content:URI থেকে—ক্লিপ তৈরি করতেnewUri()ব্যবহার করুন। -
newIntent(label, intent) - একটি
ClipDataঅবজেক্ট রিটার্ন করে, যার একমাত্রClipData.Itemঅবজেক্টটিতে একটিIntentথাকে।ClipDescriptionঅবজেক্টটির লেবেলlabelহিসেবে সেট করা হয়। এর MIME টাইপMIMETYPE_TEXT_INTENTহিসেবে সেট করা হয়।একটি
Intentঅবজেক্ট থেকে ক্লিপ তৈরি করতেnewIntent()ব্যবহার করুন।
ক্লিপবোর্ডের ডেটাকে টেক্সটে রূপান্তর করুন
আপনার অ্যাপ্লিকেশনটি শুধুমাত্র টেক্সট নিয়ে কাজ করলেও, আপনি ClipData.Item.coerceToText() মেথড ব্যবহার করে ক্লিপবোর্ড থেকে নন-টেক্সট ডেটাও কপি করতে পারেন।
এই মেথডটি ClipData.Item এর ডেটাকে টেক্সটে রূপান্তর করে এবং একটি CharSequence রিটার্ন করে। ClipData.Item.coerceToText() যে ভ্যালুটি রিটার্ন করে, তা ClipData.Item এর ডেটার ধরনের উপর ভিত্তি করে নির্ধারিত হয়:
- পাঠ্য
- যদি
ClipData.Itemএর মান text হয়—অর্থাৎ,getText()যদি null না হয়—তাহলে coerceToText() সেই টেক্সটটি রিটার্ন করে। - ইউআরআই
- যদি
ClipData.Itemএকটি URI হয়—অর্থাৎ, যদিgetUri()null না হয়—তাহলেcoerceToText()এটিকে একটি কন্টেন্ট URI হিসেবে ব্যবহার করার চেষ্টা করে।- যদি URI-টি একটি কন্টেন্ট URI হয় এবং প্রোভাইডারটি একটি টেক্সট স্ট্রিম রিটার্ন করতে পারে, তাহলে
coerceToText()একটি টেক্সট স্ট্রিম রিটার্ন করে। - যদি URI-টি একটি কন্টেন্ট URI হয় কিন্তু প্রোভাইডার কোনো টেক্সট স্ট্রিম প্রদান না করে, তাহলে
coerceToText()ফাংশনটি URI-টির একটি রিপ্রেজেন্টেশন রিটার্ন করে। এই রিপ্রেজেন্টেশনটিUri.toString()দ্বারা রিটার্ন করা রিপ্রেজেন্টেশনের মতোই হয়। - যদি URI-টি কোনো কন্টেন্ট URI না হয়, তাহলে
coerceToText()ফাংশনটি URI-টির একটি রিপ্রেজেন্টেশন রিটার্ন করে। এই রিপ্রেজেন্টেশনটিUri.toString()দ্বারা রিটার্ন করা রিপ্রেজেন্টেশনের মতোই হয়।
- যদি URI-টি একটি কন্টেন্ট URI হয় এবং প্রোভাইডারটি একটি টেক্সট স্ট্রিম রিটার্ন করতে পারে, তাহলে
- উদ্দেশ্য
- যদি
ClipData.ItemএকটিIntentহয় —অর্থাৎ, যদিgetIntent()null না হয়— তাহলেcoerceToText()এটিকে একটি Intent URI-তে রূপান্তর করে এবং সেটিই ফেরত দেয়। এর উপস্থাপনাটিIntent.toUri(URI_INTENT_SCHEME)দ্বারা ফেরত দেওয়া উপস্থাপনার মতোই।
ক্লিপবোর্ড ফ্রেমওয়ার্কটি চিত্র ২-এ সংক্ষেপে বর্ণনা করা হয়েছে। ডেটা কপি করার জন্য, একটি অ্যাপ্লিকেশন ClipboardManager গ্লোবাল ক্লিপবোর্ডে একটি ClipData অবজেক্ট রাখে। ClipData এক বা একাধিক ClipData.Item অবজেক্ট এবং একটি ClipDescription অবজেক্ট থাকে। ডেটা পেস্ট করার জন্য, একটি অ্যাপ্লিকেশন ClipData সংগ্রহ করে, ClipDescription থেকে এর MIME টাইপ নেয় এবং ClipData.Item থেকে অথবা ClipData.Item দ্বারা উল্লিখিত কন্টেন্ট প্রোভাইডার থেকে ডেটা সংগ্রহ করে।

ক্লিপবোর্ডে কপি করুন
ক্লিপবোর্ডে ডেটা কপি করতে, গ্লোবাল ClipboardManager অবজেক্টের একটি হ্যান্ডেল নিন, একটি ClipData অবজেক্ট তৈরি করুন এবং এতে একটি ClipDescription ও এক বা একাধিক ClipData.Item অবজেক্ট যোগ করুন। তারপর, তৈরি করা ClipData অবজেক্টটি ClipboardManager অবজেক্টে যোগ করুন। এই বিষয়টি নিম্নলিখিত পদ্ধতিতে আরও বিশদভাবে বর্ণনা করা হয়েছে:
- আপনি যদি কন্টেন্ট ইউআরআই ব্যবহার করে ডেটা কপি করেন, তাহলে একটি কন্টেন্ট প্রোভাইডার সেট আপ করুন।
- সিস্টেম ক্লিপবোর্ডটি নিন:
কোটলিন
when(menuItem.itemId) { ... R.id.menu_copy -> { // if the user selects copy // Gets a handle to the clipboard service. val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager } }
জাভা
... // If the user selects copy. case R.id.menu_copy: // Gets a handle to the clipboard service. ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ডেটা একটি নতুন
ClipDataঅবজেক্টে কপি করুন:- পাঠ্যের জন্য
কোটলিন
// Creates a new text clip to put on the clipboard. val clip: ClipData = ClipData.newPlainText("simple text", "Hello, World!")
জাভা
// Creates a new text clip to put on the clipboard. ClipData clip = ClipData.newPlainText("simple text", "Hello, World!");
- একটি URI এর জন্য
এই কোড স্নিপেটটি প্রোভাইডারের কন্টেন্ট URI-তে একটি রেকর্ড আইডি এনকোড করে একটি URI তৈরি করে। এই কৌশলটি "ইউআরআই-তে একটি আইডেন্টিফায়ার এনকোড করা" বিভাগে আরও বিস্তারিতভাবে আলোচনা করা হয়েছে।
কোটলিন
// Creates a Uri using a base Uri and a record ID based on the contact's last // name. Declares the base URI string. const val CONTACTS = "content://com.example.contacts" // Declares a path string for URIs, used to copy data. const val COPY_PATH = "/copy" // Declares the Uri to paste to the clipboard. val copyUri: Uri = Uri.parse("$CONTACTS$COPY_PATH/$lastName") ... // Creates a new URI clip object. The system uses the anonymous // getContentResolver() object to get MIME types from provider. The clip object's // label is "URI", and its data is the Uri previously created. val clip: ClipData = ClipData.newUri(contentResolver, "URI", copyUri)
জাভা
// Creates a Uri using a base Uri and a record ID based on the contact's last // name. Declares the base URI string. private static final String CONTACTS = "content://com.example.contacts"; // Declares a path string for URIs, used to copy data. private static final String COPY_PATH = "/copy"; // Declares the Uri to paste to the clipboard. Uri copyUri = Uri.parse(CONTACTS + COPY_PATH + "/" + lastName); ... // Creates a new URI clip object. The system uses the anonymous // getContentResolver() object to get MIME types from provider. The clip object's // label is "URI", and its data is the Uri previously created. ClipData clip = ClipData.newUri(getContentResolver(), "URI", copyUri);
- একটি অভিপ্রায়ের জন্য
এই কোড অংশটি একটি অ্যাপ্লিকেশনের জন্য একটি
Intentতৈরি করে এবং তারপর সেটিকে clip অবজেক্টে রাখে:কোটলিন
// Creates the Intent. val appIntent = Intent(this, com.example.demo.myapplication::class.java) ... // Creates a clip object with the Intent in it. Its label is "Intent" // and its data is the Intent object created previously. val clip: ClipData = ClipData.newIntent("Intent", appIntent)
জাভা
// Creates the Intent. Intent appIntent = new Intent(this, com.example.demo.myapplication.class); ... // Creates a clip object with the Intent in it. Its label is "Intent" // and its data is the Intent object created previously. ClipData clip = ClipData.newIntent("Intent", appIntent);
- পাঠ্যের জন্য
- নতুন ক্লিপ অবজেক্টটি ক্লিপবোর্ডে রাখুন:
কোটলিন
// Set the clipboard's primary clip. clipboard.setPrimaryClip(clip)
জাভা
// Set the clipboard's primary clip. clipboard.setPrimaryClip(clip);
ক্লিপবোর্ডে কপি করার সময় মতামত দিন।
অ্যাপ যখন ক্লিপবোর্ডে কোনো কন্টেন্ট কপি করে, তখন ব্যবহারকারীরা তার ভিজ্যুয়াল ফিডব্যাক আশা করেন। অ্যান্ড্রয়েড ১৩ এবং তার পরবর্তী সংস্করণগুলোতে ব্যবহারকারীদের জন্য এটি স্বয়ংক্রিয়ভাবে হয়ে যায়, কিন্তু এর আগের সংস্করণগুলোতে এটি ম্যানুয়ালি করতে হয়।
অ্যান্ড্রয়েড ১৩ থেকে, ক্লিপবোর্ডে কোনো কন্টেন্ট যোগ করা হলে সিস্টেম একটি সাধারণ ভিজ্যুয়াল কনফার্মেশন প্রদর্শন করে। নতুন কনফার্মেশনটি নিম্নলিখিত কাজগুলো করে:
- বিষয়বস্তু সফলভাবে অনুলিপি করা হয়েছে তা নিশ্চিত করে।
- অনুলিপি করা বিষয়বস্তুর একটি পূর্বরূপ দেখায়।

অ্যান্ড্রয়েড ১২এল (এপিআই লেভেল ৩২) এবং এর নিচের সংস্করণগুলোতে, ব্যবহারকারীরা নিশ্চিত হতে পারেন না যে তারা সফলভাবে কন্টেন্ট কপি করেছেন কিনা বা কী কপি করেছেন। এই ফিচারটি কপি করার পর অ্যাপগুলোর দেখানো বিভিন্ন নোটিফিকেশনকে একটি নির্দিষ্ট মানে নিয়ে আসে এবং ব্যবহারকারীদের ক্লিপবোর্ডের উপর আরও বেশি নিয়ন্ত্রণ প্রদান করে।
একই নোটিফিকেশন বারবার আসা এড়িয়ে চলুন
অ্যান্ড্রয়েড ১২এল (এপিআই লেভেল ৩২) এবং এর নিচের সংস্করণগুলোতে, কপি করার পর Toast বা Snackbar মতো উইজেট ব্যবহার করে অ্যাপের মধ্যেই ভিজ্যুয়াল ফিডব্যাক দেওয়ার মাধ্যমে ব্যবহারকারীদের সফলভাবে কপি করার বিষয়ে জানানোর পরামর্শ দেওয়া হয়।
তথ্যের পুনরাবৃত্তি এড়ানোর জন্য, অ্যান্ড্রয়েড ১৩ এবং তার পরবর্তী সংস্করণগুলোতে অ্যাপের ভেতরের কোনো কপির পরে দেখানো টোস্ট বা স্নাকবারগুলো সরিয়ে ফেলার জন্য আমরা দৃঢ়ভাবে সুপারিশ করছি।


এটি কীভাবে বাস্তবায়ন করা যায় তার একটি উদাহরণ নিচে দেওয়া হলো:
fun textCopyThenPost(textCopied:String) { val clipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager // When setting the clipboard text. clipboardManager.setPrimaryClip(ClipData.newPlainText ("", textCopied)) // Only show a toast for Android 12 and lower. if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) Toast.makeText(context, “Copied”, Toast.LENGTH_SHORT).show() }
সংবেদনশীল বিষয়বস্তু ক্লিপবোর্ডে যোগ করুন
আপনার অ্যাপ যদি ব্যবহারকারীদের পাসওয়ার্ড বা ক্রেডিট কার্ডের তথ্যের মতো সংবেদনশীল বিষয়বস্তু ক্লিপবোর্ডে কপি করার সুযোগ দেয়, তাহলে ClipboardManager.setPrimaryClip() কল করার আগে আপনাকে অবশ্যই ClipData এর ClipDescription এ একটি ফ্ল্যাগ যোগ করতে হবে। এই ফ্ল্যাগটি যোগ করলে Android 13 এবং তার পরবর্তী সংস্করণগুলিতে কপি করা বিষয়বস্তুর ভিজ্যুয়াল কনফার্মেশনে সংবেদনশীল বিষয়বস্তু প্রদর্শিত হওয়া থেকে বিরত থাকে।


সংবেদনশীল বিষয়বস্তু চিহ্নিত করতে, ClipDescription এ একটি অতিরিক্ত বুলিয়ান যোগ করুন। লক্ষ্যযুক্ত API স্তর নির্বিশেষে, সমস্ত অ্যাপকে অবশ্যই এটি করতে হবে।
// If your app is compiled with the API level 33 SDK or higher. clipData.apply { description.extras = PersistableBundle().apply { putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true) } } // If your app is compiled with a lower SDK. clipData.apply { description.extras = PersistableBundle().apply { putBoolean("android.content.extra.IS_SENSITIVE", true) } }
ক্লিপবোর্ড থেকে পেস্ট করুন
পূর্বে যেমন বর্ণনা করা হয়েছে, গ্লোবাল ক্লিপবোর্ড অবজেক্টটি নিয়ে, ক্লিপ অবজেক্টটি সংগ্রহ করে, এর ডেটা দেখে এবং সম্ভব হলে ক্লিপ অবজেক্ট থেকে ডেটা আপনার নিজের স্টোরেজে কপি করে ক্লিপবোর্ড থেকে ডেটা পেস্ট করুন। এই বিভাগে ক্লিপবোর্ডের তিন ধরনের ডেটা কীভাবে পেস্ট করতে হয় তা বিস্তারিতভাবে ব্যাখ্যা করা হয়েছে।
সাধারণ টেক্সট পেস্ট করুন
প্লেইন টেক্সট পেস্ট করতে, গ্লোবাল ক্লিপবোর্ডটি নিন এবং যাচাই করুন যে এটি প্লেইন টেক্সট রিটার্ন করতে পারে। তারপর, নিম্নলিখিত পদ্ধতিতে বর্ণিত getText() ব্যবহার করে ক্লিপ অবজেক্টটি নিন এবং এর টেক্সট আপনার নিজের স্টোরেজে কপি করুন:
-
getSystemService(CLIPBOARD_SERVICE)ব্যবহার করে গ্লোবালClipboardManagerঅবজেক্টটি নিন। এছাড়াও, পেস্ট করা টেক্সট ধারণ করার জন্য একটি গ্লোবাল ভেরিয়েবল ডিক্লেয়ার করুন:কোটলিন
var clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager var pasteData: String = ""
জাভা
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); String pasteData = "";
- বর্তমান অ্যাক্টিভিটিতে 'পেস্ট' অপশনটি চালু বা বন্ধ করার প্রয়োজন আছে কিনা তা নির্ধারণ করুন। যাচাই করুন যে ক্লিপবোর্ডে একটি ক্লিপ আছে এবং ক্লিপটিতে থাকা ডেটার ধরনটি আপনি পরিচালনা করতে পারবেন:
কোটলিন
// Gets the ID of the "paste" menu item. val pasteItem: MenuItem = menu.findItem(R.id.menu_paste) // If the clipboard doesn't contain data, disable the paste menu item. // If it does contain data, decide whether you can handle the data. pasteItem.isEnabled = when { !clipboard.hasPrimaryClip() -> { false } !(clipboard.primaryClipDescription.hasMimeType(MIMETYPE_TEXT_PLAIN)) -> { // Disables the paste menu item, since the clipboard has data but it // isn't plain text. false } else -> { // Enables the paste menu item, since the clipboard contains plain text. true } }
জাভা
// Gets the ID of the "paste" menu item. MenuItem pasteItem = menu.findItem(R.id.menu_paste); // If the clipboard doesn't contain data, disable the paste menu item. // If it does contain data, decide whether you can handle the data. if (!(clipboard.hasPrimaryClip())) { pasteItem.setEnabled(false); } else if (!(clipboard.getPrimaryClipDescription().hasMimeType(MIMETYPE_TEXT_PLAIN))) { // Disables the paste menu item, since the clipboard has data but // it isn't plain text. pasteItem.setEnabled(false); } else { // Enables the paste menu item, since the clipboard contains plain text. pasteItem.setEnabled(true); }
- ক্লিপবোর্ড থেকে ডেটা কপি করুন। কোডের এই অংশটি কেবল তখনই অ্যাক্সেসযোগ্য হবে যখন 'পেস্ট' মেনু আইটেমটি সক্রিয় থাকবে, তাই আপনি ধরে নিতে পারেন যে ক্লিপবোর্ডে সাধারণ টেক্সট রয়েছে। আপনি এখনও জানেন না যে এতে কোনো টেক্সট স্ট্রিং আছে নাকি এমন কোনো URI আছে যা সাধারণ টেক্সটকে নির্দেশ করে। নিম্নলিখিত কোড স্নিপেটটি এটি পরীক্ষা করে, কিন্তু এটি শুধুমাত্র সাধারণ টেক্সট হ্যান্ডেল করার কোড দেখায়:
কোটলিন
when (menuItem.itemId) { ... R.id.menu_paste -> { // Responds to the user selecting "paste". // Examines the item on the clipboard. If getText() doesn't return null, // the clip item contains the text. Assumes that this application can only // handle one item at a time. val item = clipboard.primaryClip.getItemAt(0) // Gets the clipboard as text. pasteData = item.text return if (pasteData != null) { // If the string contains data, then the paste operation is done. true } else { // The clipboard doesn't contain text. If it contains a URI, // attempts to get data from it. val pasteUri: Uri? = item.uri if (pasteUri != null) { // If the URI contains something, try to get text from it. // Calls a routine to resolve the URI and get data from it. // This routine isn't presented here. pasteData = resolveUri(pasteUri) true } else { // Something is wrong. The MIME type was plain text, but the // clipboard doesn't contain text or a Uri. Report an error. Log.e(TAG,"Clipboard contains an invalid data type") false } } } }
জাভা
// Responds to the user selecting "paste". case R.id.menu_paste: // Examines the item on the clipboard. If getText() does not return null, // the clip item contains the text. Assumes that this application can only // handle one item at a time. ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0); // Gets the clipboard as text. pasteData = item.getText(); // If the string contains data, then the paste operation is done. if (pasteData != null) { return true; // The clipboard doesn't contain text. If it contains a URI, attempts to get // data from it. } else { Uri pasteUri = item.getUri(); // If the URI contains something, try to get text from it. if (pasteUri != null) { // Calls a routine to resolve the URI and get data from it. // This routine isn't presented here. pasteData = resolveUri(Uri); return true; } else { // Something is wrong. The MIME type is plain text, but the // clipboard doesn't contain text or a Uri. Report an error. Log.e(TAG, "Clipboard contains an invalid data type"); return false; } }
একটি কন্টেন্ট URI থেকে ডেটা পেস্ট করুন
যদি ClipData.Item অবজেক্টটিতে একটি কন্টেন্ট URI থাকে এবং আপনি নিশ্চিত হন যে আপনি এর কোনো একটি MIME টাইপ পরিচালনা করতে পারবেন, তাহলে একটি ContentResolver তৈরি করুন এবং ডেটা পুনরুদ্ধার করার জন্য উপযুক্ত কন্টেন্ট প্রোভাইডার মেথডটি কল করুন।
নিম্নলিখিত কার্যপ্রণালীতে বর্ণনা করা হয়েছে কিভাবে ক্লিপবোর্ডে থাকা একটি কন্টেন্ট URI-এর উপর ভিত্তি করে কোনো কন্টেন্ট প্রোভাইডার থেকে ডেটা সংগ্রহ করা যায়। এটি যাচাই করে দেখে যে, অ্যাপ্লিকেশনটি ব্যবহার করতে পারে এমন কোনো MIME টাইপ প্রোভাইডারের কাছে উপলব্ধ আছে কি না।
- MIME টাইপ ধারণ করার জন্য একটি গ্লোবাল ভেরিয়েবল ঘোষণা করুন:
কোটলিন
// Declares a MIME type constant to match against the MIME types offered // by the provider. const val MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact"
জাভা
// Declares a MIME type constant to match against the MIME types offered by // the provider. public static final String MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact";
- গ্লোবাল ক্লিপবোর্ডটি নিন। এছাড়াও একটি কন্টেন্ট রিজলভার নিন যাতে আপনি কন্টেন্ট প্রোভাইডারটি অ্যাক্সেস করতে পারেন:
কোটলিন
// Gets a handle to the Clipboard Manager. val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager // Gets a content resolver instance. val cr = contentResolver
জাভা
// Gets a handle to the Clipboard Manager. ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); // Gets a content resolver instance. ContentResolver cr = getContentResolver();
- ক্লিপবোর্ড থেকে মূল ক্লিপটি নিন এবং এর বিষয়বস্তু একটি URI হিসাবে সংগ্রহ করুন:
কোটলিন
// Gets the clipboard data from the clipboard. val clip: ClipData? = clipboard.primaryClip clip?.run { // Gets the first item from the clipboard data. val item: ClipData.Item = getItemAt(0) // Tries to get the item's contents as a URI. val pasteUri: Uri? = item.uri
জাভা
// Gets the clipboard data from the clipboard. ClipData clip = clipboard.getPrimaryClip(); if (clip != null) { // Gets the first item from the clipboard data. ClipData.Item item = clip.getItemAt(0); // Tries to get the item's contents as a URI. Uri pasteUri = item.getUri();
- URI-টি একটি কন্টেন্ট URI কিনা তা
getType(Uri)কল করে পরীক্ষা করুন। যদিUriকোনো বৈধ কন্টেন্ট প্রোভাইডারকে নির্দেশ না করে, তাহলে এই মেথডটি null রিটার্ন করে।কোটলিন
// If the clipboard contains a URI reference... pasteUri?.let { // ...is this a content URI? val uriMimeType: String? = cr.getType(it)
জাভা
// If the clipboard contains a URI reference... if (pasteUri != null) { // ...is this a content URI? String uriMimeType = cr.getType(pasteUri);
- কন্টেন্ট প্রোভাইডারটি অ্যাপ্লিকেশনটির বোধগম্য কোনো MIME টাইপ সমর্থন করে কি না, তা পরীক্ষা করুন। যদি করে, তাহলে ডেটা পাওয়ার জন্য
ContentResolver.query()কল করুন। এর রিটার্ন ভ্যালুটি একটিCursor।কোটলিন
// If the return value isn't null, the Uri is a content Uri. uriMimeType?.takeIf { // Does the content provider offer a MIME type that the current // application can use? it == MIME_TYPE_CONTACT }?.apply { // Get the data from the content provider. cr.query(pasteUri, null, null, null, null)?.use { pasteCursor -> // If the Cursor contains data, move to the first record. if (pasteCursor.moveToFirst()) { // Get the data from the Cursor here. // The code varies according to the format of the data model. } // Kotlin `use` automatically closes the Cursor. } } } }
জাভা
// If the return value isn't null, the Uri is a content Uri. if (uriMimeType != null) { // Does the content provider offer a MIME type that the current // application can use? if (uriMimeType.equals(MIME_TYPE_CONTACT)) { // Get the data from the content provider. Cursor pasteCursor = cr.query(uri, null, null, null, null); // If the Cursor contains data, move to the first record. if (pasteCursor != null) { if (pasteCursor.moveToFirst()) { // Get the data from the Cursor here. // The code varies according to the format of the data model. } } // Close the Cursor. pasteCursor.close(); } } } }
একটি অভিপ্রায় পেস্ট করুন
একটি ইন্টেন্ট পেস্ট করতে, প্রথমে গ্লোবাল ক্লিপবোর্ডটি নিন। ClipData.Item অবজেক্টটি পরীক্ষা করে দেখুন যে এর মধ্যে কোনো Intent আছে কিনা। তারপর ইন্টেন্টটি আপনার নিজের স্টোরেজে কপি করার জন্য getIntent() কল করুন। নিচের কোড স্নিপেটটি এটি প্রদর্শন করে:
কোটলিন
// Gets a handle to the Clipboard Manager. val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager // Checks whether the clip item contains an Intent by testing whether // getIntent() returns null. val pasteIntent: Intent? = clipboard.primaryClip?.getItemAt(0)?.intent if (pasteIntent != null) { // Handle the Intent. } else { // Ignore the clipboard, or issue an error if // you expect an Intent to be on the clipboard. }
জাভা
// Gets a handle to the Clipboard Manager. ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); // Checks whether the clip item contains an Intent, by testing whether // getIntent() returns null. Intent pasteIntent = clipboard.getPrimaryClip().getItemAt(0).getIntent(); if (pasteIntent != null) { // Handle the Intent. } else { // Ignore the clipboard, or issue an error if // you expect an Intent to be on the clipboard. }
আপনার অ্যাপ যখন ক্লিপবোর্ডের ডেটা অ্যাক্সেস করে তখন সিস্টেম নোটিফিকেশন দেখানো হয়।
অ্যান্ড্রয়েড ১২ (এপিআই লেভেল ৩১) এবং এর পরবর্তী সংস্করণগুলোতে, আপনার অ্যাপ যখন getPrimaryClip() কল করে, তখন সিস্টেম সাধারণত একটি টোস্ট মেসেজ দেখায়। মেসেজের ভেতরের টেক্সটটি নিম্নলিখিত ফরম্যাটে থাকে:
APP pasted from your clipboard
আপনার অ্যাপ নিম্নলিখিত কাজগুলোর মধ্যে কোনো একটি করলে সিস্টেম কোনো টোস্ট মেসেজ দেখায় না:
- আপনার নিজের অ্যাপ থেকে
ClipDataঅ্যাক্সেস করে। - একটি নির্দিষ্ট অ্যাপ থেকে বারবার
ClipDataঅ্যাক্সেস করা হয়। এই টোস্টটি কেবল তখনই প্রদর্শিত হয়, যখন আপনার অ্যাপটি প্রথমবারের মতো সেই অ্যাপ থেকে ডেটা অ্যাক্সেস করে। - ক্লিপ অবজেক্টের মেটাডেটা পুনরুদ্ধার করে, যেমন getPrimaryClip
getPrimaryClipDescription()getPrimaryClip()) কল করে।
জটিল ডেটা কপি করতে কন্টেন্ট প্রোভাইডার ব্যবহার করুন
কন্টেন্ট প্রোভাইডাররা ডাটাবেস রেকর্ড বা ফাইল স্ট্রিমের মতো জটিল ডেটা কপি করা সমর্থন করে। ডেটা কপি করতে, ক্লিপবোর্ডে একটি কন্টেন্ট URI রাখুন। এরপর পেস্টিং অ্যাপ্লিকেশনগুলো ক্লিপবোর্ড থেকে এই URI-টি নিয়ে ডাটাবেস ডেটা বা ফাইল স্ট্রিম ডেসক্রিপ্টর পুনরুদ্ধার করতে এটি ব্যবহার করে।
যেহেতু পেস্ট করার অ্যাপ্লিকেশনটির কাছে আপনার ডেটার শুধুমাত্র কন্টেন্ট ইউআরআই থাকে, তাই কোন ডেটাটি পুনরুদ্ধার করতে হবে তা তার জানা প্রয়োজন। আপনি ইউআরআই-এর মধ্যেই ডেটার জন্য একটি আইডেন্টিফায়ার এনকোড করে এই তথ্যটি সরবরাহ করতে পারেন, অথবা আপনি একটি অনন্য ইউআরআই প্রদান করতে পারেন যা আপনার কাঙ্ক্ষিত ডেটাটি ফেরত দেবে। আপনি কোন পদ্ধতিটি বেছে নেবেন তা আপনার ডেটার বিন্যাসের উপর নির্ভর করে।
নিম্নলিখিত বিভাগগুলিতে ইউআরআই (URI) সেট আপ করা, জটিল ডেটা প্রদান করা এবং ফাইল স্ট্রিম সরবরাহ করার পদ্ধতি বর্ণনা করা হয়েছে। এই বর্ণনাগুলি এমনভাবে করা হয়েছে যেন আপনি কন্টেন্ট প্রোভাইডার ডিজাইনের সাধারণ নীতিগুলির সাথে পরিচিত।
URI-তে একটি শনাক্তকারীকে এনকোড করুন
URI ব্যবহার করে ক্লিপবোর্ডে ডেটা কপি করার একটি কার্যকরী কৌশল হলো, URI-টির মধ্যেই ডেটার জন্য একটি আইডেন্টিফায়ার এনকোড করে দেওয়া। এরপর আপনার কন্টেন্ট প্রোভাইডার URI থেকে আইডেন্টিফায়ারটি নিয়ে ডেটা পুনরুদ্ধার করতে পারে। পেস্ট করার অ্যাপ্লিকেশনটির আইডেন্টিফায়ারটির অস্তিত্ব সম্পর্কে জানার প্রয়োজন নেই। এটিকে শুধু ক্লিপবোর্ড থেকে আপনার "রেফারেন্স"—অর্থাৎ URI এবং আইডেন্টিফায়ার—নিয়ে আপনার কন্টেন্ট প্রোভাইডারকে দিতে হবে এবং ডেটা ফেরত পেয়ে যাবে।
সাধারণত কোনো কন্টেন্ট URI-এর শেষে একটি আইডেন্টিফায়ার যুক্ত করে সেটিকে এনকোড করা হয়। উদাহরণস্বরূপ, ধরুন আপনি আপনার প্রোভাইডার URI-কে নিম্নলিখিত স্ট্রিং হিসাবে সংজ্ঞায়িত করেছেন:
"content://com.example.contacts"
আপনি যদি এই URI-তে একটি নাম এনকোড করতে চান, তাহলে নিম্নলিখিত কোড স্নিপেটটি ব্যবহার করুন:
কোটলিন
val uriString = "content://com.example.contacts/Smith" // uriString now contains content://com.example.contacts/Smith. // Generates a uri object from the string representation. val copyUri = Uri.parse(uriString)
জাভা
String uriString = "content://com.example.contacts" + "/" + "Smith"; // uriString now contains content://com.example.contacts/Smith. // Generates a uri object from the string representation. Uri copyUri = Uri.parse(uriString);
আপনি যদি ইতিমধ্যেই কোনো কন্টেন্ট প্রোভাইডার ব্যবহার করে থাকেন, তাহলে আপনি একটি নতুন URI পাথ যোগ করতে চাইতে পারেন যা নির্দেশ করবে যে URI-টি কপি করার জন্য। উদাহরণস্বরূপ, ধরুন আপনার কাছে ইতিমধ্যেই নিম্নলিখিত URI পাথগুলো রয়েছে:
"content://com.example.contacts/people" "content://com.example.contacts/people/detail" "content://com.example.contacts/people/images"
আপনি URI কপি করার জন্য আরেকটি পাথ যোগ করতে পারেন:
"content://com.example.contacts/copying"
এরপর আপনি প্যাটার্ন-ম্যাচিংয়ের মাধ্যমে একটি 'কপি' URI শনাক্ত করতে পারবেন এবং কপি ও পেস্টের জন্য নির্দিষ্ট কোড দিয়ে তা পরিচালনা করতে পারবেন।
আপনি সাধারণত এনকোডিং কৌশলটি ব্যবহার করেন যদি আপনি আপনার ডেটা সংগঠিত করার জন্য আগে থেকেই কোনো কন্টেন্ট প্রোভাইডার, অভ্যন্তরীণ ডেটাবেস বা অভ্যন্তরীণ টেবিল ব্যবহার করে থাকেন। এই ক্ষেত্রে, আপনার কাছে একাধিক ডেটা থাকে যা আপনি কপি করতে চান এবং সম্ভবত প্রতিটি ডেটার জন্য একটি অনন্য শনাক্তকারীও থাকে। পেস্টিং অ্যাপ্লিকেশন থেকে আসা একটি কোয়েরির জবাবে, আপনি তার শনাক্তকারী দ্বারা ডেটাটি খুঁজে বের করে তা ফেরত দিতে পারেন।
যদি আপনার কাছে একাধিক ডেটা না থাকে, তাহলে সম্ভবত আপনার কোনো আইডেন্টিফায়ার এনকোড করার প্রয়োজন নেই। আপনি আপনার প্রোভাইডারের জন্য একটি অনন্য URI ব্যবহার করতে পারেন। কোনো কোয়েরির জবাবে, আপনার প্রোভাইডার তার কাছে বর্তমানে থাকা ডেটা ফেরত দেয়।
ডেটা কাঠামো কপি করুন
ContentProvider কম্পোনেন্টের একটি সাবক্লাস হিসেবে জটিল ডেটা কপি ও পেস্ট করার জন্য একটি কন্টেন্ট প্রোভাইডার সেট আপ করুন। ক্লিপবোর্ডে রাখা URI-টি এনকোড করুন, যাতে এটি আপনার সরবরাহ করতে চাওয়া সুনির্দিষ্ট রেকর্ডটিকে নির্দেশ করে। এছাড়াও, আপনার অ্যাপ্লিকেশনের বর্তমান অবস্থা বিবেচনা করুন:
- আপনার যদি আগে থেকেই একটি কন্টেন্ট প্রোভাইডার থাকে, তবে আপনি এর কার্যকারিতা বাড়াতে পারেন। ডেটা পেস্ট করতে চায় এমন অ্যাপ্লিকেশন থেকে আসা URI-গুলো হ্যান্ডেল করার জন্য আপনাকে হয়তো শুধু এর
query()মেথডটি পরিবর্তন করতে হবে। আপনি সম্ভবত একটি "copy" URI প্যাটার্ন হ্যান্ডেল করার জন্য মেথডটি পরিবর্তন করতে চাইবেন। - আপনার অ্যাপ্লিকেশনে যদি কোনো অভ্যন্তরীণ ডেটাবেস থাকে, তবে সেখান থেকে ডেটা কপি করার সুবিধার্থে আপনি এই ডেটাবেসটিকে একটি কন্টেন্ট প্রোভাইডারে স্থানান্তর করতে চাইতে পারেন।
- যদি আপনি ডেটাবেস ব্যবহার না করেন, তাহলে একটি সাধারণ কন্টেন্ট প্রোভাইডার তৈরি করতে পারেন, যার একমাত্র উদ্দেশ্য হবে ক্লিপবোর্ড থেকে পেস্ট করা অ্যাপ্লিকেশনগুলোকে ডেটা সরবরাহ করা।
কন্টেন্ট প্রোভাইডারে, অন্তত নিম্নলিখিত মেথডগুলো ওভাররাইড করুন:
-
query() - পেস্ট করার অ্যাপ্লিকেশনগুলো ধরে নেয় যে, আপনি ক্লিপবোর্ডে যে URI রেখেছেন, তা ব্যবহার করে এই পদ্ধতির মাধ্যমে তারা আপনার ডেটা পেতে পারে। কপি করা সমর্থন করার জন্য, এই পদ্ধতিটিকে এমন URI শনাক্ত করতে দিন যেগুলোতে একটি বিশেষ "কপি" পাথ রয়েছে। এরপর আপনার অ্যাপ্লিকেশনটি ক্লিপবোর্ডে রাখার জন্য একটি "কপি" URI তৈরি করতে পারবে, যেটিতে কপি পাথ এবং আপনি যে নির্দিষ্ট রেকর্ডটি কপি করতে চান তার একটি পয়েন্টার থাকবে।
-
getType() - এই মেথডটিকে অবশ্যই সেই ডেটার MIME টাইপগুলো রিটার্ন করতে হবে যা আপনি কপি করতে চান।
newUri()মেথডটি নতুনClipDataঅবজেক্টে MIME টাইপগুলো রাখার জন্যgetType()মেথডকে কল করে।জটিল ডেটার জন্য MIME টাইপগুলো কন্টেন্ট প্রোভাইডার্স -এ বর্ণনা করা হয়েছে।
আপনার insert() বা update() এর মতো অন্য কোনো কন্টেন্ট প্রোভাইডার মেথড থাকার প্রয়োজন নেই। একটি পেস্টিং অ্যাপ্লিকেশনের শুধু আপনার প্রোভাইডার থেকে সমর্থিত MIME টাইপগুলো সংগ্রহ করে ডেটা কপি করতে হবে। যদি আপনার এই মেথডগুলো আগে থেকেই থাকে, তবে সেগুলো কপি অপারেশনে কোনো বাধা সৃষ্টি করবে না।
নিম্নলিখিত কোড স্নিপেটগুলি দেখায় কিভাবে আপনার অ্যাপ্লিকেশনটি জটিল ডেটা কপি করার জন্য সেট আপ করতে হয়:
আপনার অ্যাপ্লিকেশনের গ্লোবাল কনস্ট্যান্টে, একটি বেস URI স্ট্রিং এবং ডেটা কপি করার জন্য ব্যবহৃত URI স্ট্রিং শনাক্তকারী একটি পাথ ঘোষণা করুন। এছাড়াও, কপি করা ডেটার জন্য একটি MIME টাইপ ঘোষণা করুন।
কোটলিন
// Declares the base URI string. private const val CONTACTS = "content://com.example.contacts" // Declares a path string for URIs that you use to copy data. private const val COPY_PATH = "/copy" // Declares a MIME type for the copied data. const val MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact"
জাভা
// Declares the base URI string. private static final String CONTACTS = "content://com.example.contacts"; // Declares a path string for URIs that you use to copy data. private static final String COPY_PATH = "/copy"; // Declares a MIME type for the copied data. public static final String MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact";
- যে অ্যাক্টিভিটি থেকে ব্যবহারকারীরা ডেটা কপি করেন, সেখানে ক্লিপবোর্ডে ডেটা কপি করার জন্য কোড সেট আপ করুন। কপি করার অনুরোধের জবাবে, URI-টি ক্লিপবোর্ডে রাখুন।
কোটলিন
class MyCopyActivity : Activity() { ... when(item.itemId) { R.id.menu_copy -> { // The user has selected a name and is requesting a copy. // Appends the last name to the base URI. // The name is stored in "lastName". uriString = "$CONTACTS$COPY_PATH/$lastName" // Parses the string into a URI. val copyUri: Uri? = Uri.parse(uriString) // Gets a handle to the clipboard service. val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clip: ClipData = ClipData.newUri(contentResolver, "URI", copyUri) // Sets the clipboard's primary clip. clipboard.setPrimaryClip(clip) } }
জাভা
public class MyCopyActivity extends Activity { ... // The user has selected a name and is requesting a copy. case R.id.menu_copy: // Appends the last name to the base URI. // The name is stored in "lastName". uriString = CONTACTS + COPY_PATH + "/" + lastName; // Parses the string into a URI. Uri copyUri = Uri.parse(uriString); // Gets a handle to the clipboard service. ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newUri(getContentResolver(), "URI", copyUri); // Sets the clipboard's primary clip. clipboard.setPrimaryClip(clip);
আপনার কন্টেন্ট প্রোভাইডারের গ্লোবাল স্কোপে, একটি URI ম্যাচিং টুল তৈরি করুন এবং এমন একটি URI প্যাটার্ন যোগ করুন যা আপনার ক্লিপবোর্ডে রাখা URI-গুলোর সাথে মেলে।
কোটলিন
// A Uri Match object that simplifies matching content URIs to patterns. private val sUriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply { // Adds a matcher for the content URI. It matches. // "content://com.example.contacts/copy/*" addURI(CONTACTS, "names/*", GET_SINGLE_CONTACT) } // An integer to use in switching based on the incoming URI pattern. private const val GET_SINGLE_CONTACT = 0 ... class MyCopyProvider : ContentProvider() { ... }
জাভা
public class MyCopyProvider extends ContentProvider { ... // A Uri Match object that simplifies matching content URIs to patterns. private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); // An integer to use in switching based on the incoming URI pattern. private static final int GET_SINGLE_CONTACT = 0; ... // Adds a matcher for the content URI. It matches // "content://com.example.contacts/copy/*" sUriMatcher.addURI(CONTACTS, "names/*", GET_SINGLE_CONTACT);
query()মেথডটি সেট আপ করুন। আপনি কীভাবে কোড করছেন তার উপর নির্ভর করে এই মেথডটি বিভিন্ন URI প্যাটার্ন পরিচালনা করতে পারে, কিন্তু শুধুমাত্র ক্লিপবোর্ডে কপি করার অপারেশনের প্যাটার্নটিই দেখানো হয়।কোটলিন
// Sets up your provider's query() method. override fun query( uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String? ): Cursor? { ... // When based on the incoming content URI: when(sUriMatcher.match(uri)) { GET_SINGLE_CONTACT -> { // Queries and returns the contact for the requested name. Decodes // the incoming URI, queries the data model based on the last name, // and returns the result as a Cursor. } } ... }
জাভা
// Sets up your provider's query() method. public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { ... // Switch based on the incoming content URI. switch (sUriMatcher.match(uri)) { case GET_SINGLE_CONTACT: // Queries and returns the contact for the requested name. Decodes the // incoming URI, queries the data model based on the last name, and // returns the result as a Cursor. ... }
কপি করা ডেটার জন্য উপযুক্ত MIME টাইপ রিটার্ন করতে
getType()মেথডটি সেট আপ করুন:কোটলিন
// Sets up your provider's getType() method. override fun getType(uri: Uri): String? { ... return when(sUriMatcher.match(uri)) { GET_SINGLE_CONTACT -> MIME_TYPE_CONTACT ... } }
জাভা
// Sets up your provider's getType() method. public String getType(Uri uri) { ... switch (sUriMatcher.match(uri)) { case GET_SINGLE_CONTACT: return (MIME_TYPE_CONTACT); ... } }
"কন্টেন্ট ইউআরআই থেকে ডেটা পেস্ট করুন" বিভাগে বর্ণনা করা হয়েছে কীভাবে ক্লিপবোর্ড থেকে একটি কন্টেন্ট ইউআরআই পাওয়া যায় এবং তা ব্যবহার করে ডেটা আনা ও পেস্ট করা যায়।
ডেটা স্ট্রিম কপি করুন
আপনি স্ট্রিম হিসেবে বিপুল পরিমাণ টেক্সট এবং বাইনারি ডেটা কপি ও পেস্ট করতে পারেন। ডেটাগুলো নিম্নলিখিত ধরনের হতে পারে:
- আসল ডিভাইসে সংরক্ষিত ফাইলগুলি
- সকেট থেকে স্ট্রিম
- প্রোভাইডারের অন্তর্নিহিত ডেটাবেস সিস্টেমে বিপুল পরিমাণ ডেটা সংরক্ষিত থাকে।
ডেটা স্ট্রিমের জন্য একটি কন্টেন্ট প্রোভাইডার Cursor অবজেক্টের পরিবর্তে AssetFileDescriptor এর মতো একটি ফাইল ডেসক্রিপ্টর অবজেক্টের মাধ্যমে তার ডেটাতে অ্যাক্সেস প্রদান করে। পেস্টিং অ্যাপ্লিকেশনটি এই ফাইল ডেসক্রিপ্টর ব্যবহার করে ডেটা স্ট্রিমটি পড়ে।
প্রোভাইডারের সাহায্যে ডেটা স্ট্রিম কপি করার জন্য আপনার অ্যাপ্লিকেশনটি সেট আপ করতে, এই ধাপগুলো অনুসরণ করুন:
- যে ডেটা স্ট্রিমটি আপনি ক্লিপবোর্ডে রাখছেন, তার জন্য একটি কন্টেন্ট ইউআরআই (Content URI) সেট আপ করুন। এটি করার জন্য নিম্নলিখিত বিকল্পগুলি রয়েছে:
- "ইউআরআই-তে একটি আইডেন্টিফায়ার এনকোড করুন" বিভাগে বর্ণিত পদ্ধতি অনুসারে ডেটা স্ট্রিমের জন্য একটি আইডেন্টিফায়ারকে ইউআরআই- তে এনকোড করুন, এবং তারপরে আপনার প্রোভাইডারে একটি টেবিল রক্ষণাবেক্ষণ করুন যাতে আইডেন্টিফায়ার এবং সংশ্লিষ্ট স্ট্রিমের নাম থাকে।
- স্ট্রিমের নামটি সরাসরি URI-তে এনকোড করুন।
- একটি অনন্য URI ব্যবহার করুন যা প্রোভাইডার থেকে সর্বদা বর্তমান স্ট্রিমটি ফেরত দেয়। আপনি যদি এই বিকল্পটি ব্যবহার করেন, তবে মনে রাখবেন যে যখনই আপনি URI ব্যবহার করে স্ট্রিমটি ক্লিপবোর্ডে কপি করবেন, তখন আপনার প্রোভাইডারকে একটি ভিন্ন স্ট্রিমে নির্দেশ করার জন্য আপডেট করতে হবে।
- আপনি যে ধরনের ডেটা স্ট্রিম সরবরাহ করার পরিকল্পনা করছেন, তার প্রত্যেকটির জন্য একটি MIME টাইপ প্রদান করুন। পেস্টিং অ্যাপ্লিকেশনগুলির এই তথ্য প্রয়োজন হয়, যাতে তারা ক্লিপবোর্ডে থাকা ডেটা পেস্ট করতে পারবে কি না তা নির্ধারণ করতে পারে।
-
ContentProviderএর এমন একটি মেথড ইমপ্লিমেন্ট করুন যা একটি স্ট্রিমের জন্য ফাইল ডেসক্রিপ্টর রিটার্ন করে। আপনি যদি কন্টেন্ট URI-তে আইডেন্টিফায়ার এনকোড করেন, তাহলে কোন স্ট্রিমটি খুলতে হবে তা নির্ধারণ করতে এই মেথডটি ব্যবহার করুন। - ডেটা স্ট্রিমটি ক্লিপবোর্ডে কপি করতে, কন্টেন্ট URI তৈরি করুন এবং সেটি ক্লিপবোর্ডে রাখুন।
একটি ডেটা স্ট্রিম পেস্ট করার জন্য, অ্যাপ্লিকেশনটি ক্লিপবোর্ড থেকে ক্লিপটি নেয়, URI সংগ্রহ করে এবং স্ট্রিমটি খোলার জন্য ContentResolver ফাইল ডেসক্রিপ্টর মেথডে কল করতে সেটি ব্যবহার করে। ContentResolver মেথডটি কন্টেন্ট URI পাস করে সংশ্লিষ্ট ContentProvider মেথডকে কল করে। আপনার প্রোভাইডারটি ContentResolver মেথডে ফাইল ডেসক্রিপ্টরটি ফেরত পাঠায়। এরপর পেস্টকারী অ্যাপ্লিকেশনটির দায়িত্ব হলো স্ট্রিম থেকে ডেটা পড়া।
নিম্নলিখিত তালিকাটি একটি কন্টেন্ট প্রোভাইডারের জন্য সবচেয়ে গুরুত্বপূর্ণ ফাইল ডেসক্রিপ্টর মেথডগুলো দেখায়। এদের প্রত্যেকটির একটি সংশ্লিষ্ট ContentResolver মেথড রয়েছে, যার নামের শেষে "Descriptor" স্ট্রিংটি যুক্ত করা থাকে। উদাহরণস্বরূপ, openAssetFile() এর ContentResolver অ্যানালগ হলো openAssetFileDescriptor() ।
-
openTypedAssetFile() এই মেথডটি একটি অ্যাসেট ফাইল ডেসক্রিপ্টর রিটার্ন করে, তবে শুধুমাত্র যদি প্রদত্ত MIME টাইপটি প্রোভাইডার দ্বারা সমর্থিত হয়। কলার—অর্থাৎ যে অ্যাপ্লিকেশনটি পেস্ট করছে—একটি MIME টাইপ প্যাটার্ন প্রদান করে। যে অ্যাপ্লিকেশনটি ক্লিপবোর্ডে একটি URI কপি করে, তার কন্টেন্ট প্রোভাইডার যদি সেই MIME টাইপটি প্রদান করতে পারে তবে একটি
AssetFileDescriptorফাইল হ্যান্ডেল রিটার্ন করে এবং যদি না পারে তবে একটি এক্সেপশন থ্রো করে।এই পদ্ধতিটি ফাইলের উপবিভাগগুলো পরিচালনা করে। কন্টেন্ট প্রোভাইডার কর্তৃক ক্লিপবোর্ডে কপি করা অ্যাসেটগুলো পড়ার জন্য আপনি এটি ব্যবহার করতে পারেন।
-
openAssetFile() - এই পদ্ধতিটি
openTypedAssetFile()এর একটি আরও সাধারণ রূপ। এটি অনুমোদিত MIME টাইপগুলির জন্য ফিল্টার করে না, তবে এটি ফাইলের উপবিভাগ পড়তে পারে। -
openFile() - এটি
openAssetFile()এর একটি আরও সাধারণ রূপ। এটি ফাইলের উপবিভাগ পড়তে পারে না।
আপনি ঐচ্ছিকভাবে আপনার ফাইল ডেসক্রিপ্টর মেথডের সাথে openPipeHelper() মেথডটি ব্যবহার করতে পারেন। এটি পেস্টিং অ্যাপ্লিকেশনকে একটি পাইপ ব্যবহার করে ব্যাকগ্রাউন্ড থ্রেডে স্ট্রিম ডেটা পড়তে দেয়। এই মেথডটি ব্যবহার করতে, ContentProvider.PipeDataWriter ইন্টারফেসটি ইমপ্লিমেন্ট করুন।
কার্যকরী কপি এবং পেস্ট কার্যকারিতা ডিজাইন করুন
আপনার অ্যাপ্লিকেশনের জন্য কার্যকর কপি ও পেস্ট কার্যকারিতা ডিজাইন করতে, এই বিষয়গুলো মনে রাখবেন:
- যেকোনো সময়ে ক্লিপবোর্ডে কেবল একটিই ক্লিপ থাকে। সিস্টেমের যেকোনো অ্যাপ্লিকেশন দ্বারা নতুন করে কপি করলে আগের ক্লিপটি মুছে যায়। যেহেতু ব্যবহারকারী আপনার অ্যাপ্লিকেশন থেকে অন্য কোথাও গিয়ে কপি করার পর আবার ফিরে আসতে পারেন, তাই আপনি ধরে নিতে পারবেন না যে ক্লিপবোর্ডে সেই ক্লিপটিই আছে যা ব্যবহারকারী আগে আপনার অ্যাপ্লিকেশনে কপি করেছিলেন।
- একটি ক্লিপে একাধিক
ClipData.Itemঅবজেক্ট থাকার উদ্দেশ্য হলো, একটিমাত্র সিলেকশনের বিভিন্ন ধরনের রেফারেন্সের পরিবর্তে একাধিক সিলেকশন কপি ও পেস্ট করা। সাধারণত আপনি চাইবেন একটি ক্লিপের সমস্তClipData.Itemঅবজেক্টের গঠন একই রকম হোক। অর্থাৎ, সেগুলোকে অবশ্যই সাধারণ টেক্সট, কন্টেন্ট ইউআরআই বাIntentহতে হবে এবং এগুলোর কোনো মিশ্রণ থাকা চলবে না। - ডেটা প্রদান করার সময়, আপনি বিভিন্ন MIME উপস্থাপনা অফার করতে পারেন। আপনার সমর্থিত MIME টাইপগুলি
ClipDescriptionএ যোগ করুন, এবং তারপর আপনার কন্টেন্ট প্রোভাইডারে MIME টাইপগুলি প্রয়োগ করুন। - যখন আপনি ক্লিপবোর্ড থেকে ডেটা নেন, তখন আপনার অ্যাপ্লিকেশনটির দায়িত্ব হলো উপলব্ধ MIME টাইপগুলো পরীক্ষা করা এবং তারপর সেগুলোর মধ্যে কোনটি ব্যবহার করা হবে (যদি কোনোটি ব্যবহার করার প্রয়োজন হয়) তা স্থির করা। এমনকি যদি ক্লিপবোর্ডে কোনো ক্লিপ থাকে এবং ব্যবহারকারী পেস্ট করার অনুরোধ করেন, তবুও আপনার অ্যাপ্লিকেশনটি পেস্ট করতে বাধ্য নয়। যদি MIME টাইপটি সামঞ্জস্যপূর্ণ হয়, তবে পেস্ট করুন। আপনি
coerceToText()ব্যবহার করে ক্লিপবোর্ডের ডেটাকে টেক্সটে রূপান্তর করতে পারেন। যদি আপনার অ্যাপ্লিকেশনটি উপলব্ধ MIME টাইপগুলোর মধ্যে একাধিক সমর্থন করে, তবে আপনি ব্যবহারকারীকে বেছে নিতে দিতে পারেন যে কোনটি ব্যবহার করা হবে।
