কপি এবং পেস্ট করুন

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

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

যেহেতু কাঠামোর একটি অংশ কন্টেন্ট প্রোভাইডার ব্যবহার করে, তাই এই নথিতে Android কন্টেন্ট প্রোভাইডার API-এর সাথে কিছুটা পরিচিতি অনুমান করা হয়েছে, যা কন্টেন্ট প্রোভাইডার -এ বর্ণিত আছে।

ক্লিপবোর্ডে কন্টেন্ট কপি করার সময় ব্যবহারকারীরা প্রতিক্রিয়া আশা করেন, তাই কপি এবং পেস্ট করার ক্ষমতা প্রদানকারী ফ্রেমওয়ার্ক ছাড়াও, অ্যান্ড্রয়েড ১৩ (এপিআই লেভেল ৩৩) এবং তার উচ্চতর সংস্করণে কপি করার সময় ব্যবহারকারীদের একটি ডিফল্ট UI দেখায়। এই বৈশিষ্ট্যের কারণে, ডুপ্লিকেট নোটিফিকেশনের ঝুঁকি রয়েছে। আপনি "ডুপ্লিকেট নোটিফিকেশন এড়িয়ে চলুন" বিভাগে এই এজ কেস সম্পর্কে আরও জানতে পারবেন।

Android 13 ক্লিপবোর্ড বিজ্ঞপ্তি দেখানো একটি অ্যানিমেশন
চিত্র ১। অ্যান্ড্রয়েড ১৩ এবং তার পরবর্তী সংস্করণে ক্লিপবোর্ডে কন্টেন্ট প্রবেশ করলে UI দেখানো হয়েছে।

Android 12L (API লেভেল 32) এবং তার নিচের ভার্সনে কপি করার সময় ব্যবহারকারীদের ম্যানুয়ালি প্রতিক্রিয়া জানান। এই ডকুমেন্টে এর জন্য সুপারিশ দেখুন।

ক্লিপবোর্ড ফ্রেমওয়ার্ক

যখন আপনি ক্লিপবোর্ড ফ্রেমওয়ার্ক ব্যবহার করেন, তখন একটি ক্লিপ অবজেক্টে ডেটা রাখুন, এবং তারপর ক্লিপ অবজেক্টটিকে সিস্টেম-ওয়াইড ক্লিপবোর্ডে রাখুন। ক্লিপ অবজেক্টটি তিনটি রূপের মধ্যে একটি নিতে পারে:

টেক্সট
একটি টেক্সট স্ট্রিং। স্ট্রিংটি সরাসরি ক্লিপ অবজেক্টে রাখুন, যা আপনি ক্লিপবোর্ডে রাখবেন। স্ট্রিংটি পেস্ট করার জন্য, ক্লিপবোর্ড থেকে ক্লিপ অবজেক্টটি নিন এবং স্ট্রিংটি আপনার অ্যাপ্লিকেশনের স্টোরেজে কপি করুন।
ইউআরআই
Uri অবজেক্ট যেকোনো ধরণের URI প্রতিনিধিত্ব করে। এটি মূলত একটি কন্টেন্ট প্রদানকারী থেকে জটিল ডেটা কপি করার জন্য। ডেটা কপি করতে, একটি Uri অবজেক্টকে একটি ক্লিপ অবজেক্টে রাখুন এবং ক্লিপ অবজেক্টটি ক্লিপবোর্ডে রাখুন। ডেটা পেস্ট করতে, ক্লিপ অবজেক্টটি পান, Uri অবজেক্টটি পান, এটি একটি ডেটা সোর্সে সমাধান করুন, যেমন একটি কন্টেন্ট প্রদানকারী, এবং উৎস থেকে ডেটা আপনার অ্যাপ্লিকেশনের স্টোরেজে কপি করুন।
অভিপ্রায়
একটি Intent । এটি অ্যাপ্লিকেশন শর্টকাট কপি করা সমর্থন করে। ডেটা কপি করতে, একটি Intent তৈরি করুন, এটি একটি clip অবজেক্টে রাখুন এবং clip অবজেক্টটি ক্লিপবোর্ডে রাখুন। ডেটা পেস্ট করতে, clip অবজেক্টটি পান এবং তারপর Intent অবজেক্টটি আপনার অ্যাপ্লিকেশনের মেমরি এরিয়ায় কপি করুন।

ক্লিপবোর্ডে একবারে কেবল একটি ক্লিপ অবজেক্ট থাকে। যখন কোনও অ্যাপ্লিকেশন ক্লিপবোর্ডে একটি ক্লিপ অবজেক্ট রাখে, তখন পূর্ববর্তী ক্লিপ অবজেক্টটি অদৃশ্য হয়ে যায়।

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

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

ক্লিপবোর্ড ক্লাস

এই বিভাগটি ক্লিপবোর্ড ফ্রেমওয়ার্ক দ্বারা ব্যবহৃত ক্লাসগুলি বর্ণনা করে।

ক্লিপবোর্ড ম্যানেজার

অ্যান্ড্রয়েড সিস্টেম ক্লিপবোর্ডটি গ্লোবাল ClipboardManager ক্লাস দ্বারা প্রতিনিধিত্ব করা হয়। এই ক্লাসটি সরাসরি ইনস্ট্যান্টিয়েট করবেন না। পরিবর্তে, getSystemService(CLIPBOARD_SERVICE) ব্যবহার করে এটির একটি রেফারেন্স পান।

ক্লিপডেটা, ক্লিপডেটা.আইটেম, এবং ক্লিপডেসক্রিপশন

ক্লিপবোর্ডে ডেটা যোগ করার জন্য, একটি 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 একটি content URI হয়—অর্থাৎ, যদি Uri.getScheme() content: —পদ্ধতিটি resolver এ প্রদত্ত ContentResolver অবজেক্ট ব্যবহার করে কন্টেন্ট প্রদানকারীর কাছ থেকে উপলব্ধ MIME প্রকারগুলি পুনরুদ্ধার করে। তারপর এটি সেগুলিকে ClipDescription এ সংরক্ষণ করে। যে URI একটি content: URI নয় তার জন্য, পদ্ধতিটি MIME প্রকারটিকে MIMETYPE_TEXT_URILIST এ সেট করে।

একটি URI থেকে একটি ক্লিপ তৈরি করতে newUri() ব্যবহার করুন—বিশেষ করে একটি content: URI।

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 টেক্সট হয়—অর্থাৎ, যদি 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() দ্বারা প্রদত্ত উপস্থাপনার মতোই।
অভিপ্রায়
যদি 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 অবজেক্টে যোগ করুন। এটি নিম্নলিখিত পদ্ধতিতে আরও বর্ণনা করা হয়েছে:

  1. যদি আপনি একটি কন্টেন্ট URI ব্যবহার করে ডেটা কপি করেন, তাহলে একটি কন্টেন্ট প্রদানকারী সেট আপ করুন।
  2. সিস্টেম ক্লিপবোর্ডটি পান:

    কোটলিন

    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);
  3. একটি নতুন 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 তৈরি করে। এই কৌশলটি 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 তৈরি করে এবং তারপর এটি ক্লিপ অবজেক্টে রাখে:

      কোটলিন

      // 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);
  4. নতুন ক্লিপ অবজেক্টটি ক্লিপবোর্ডে রাখুন:

    কোটলিন

    // Set the clipboard's primary clip.
    clipboard.setPrimaryClip(clip)

    জাভা

    // Set the clipboard's primary clip.
    clipboard.setPrimaryClip(clip);

ক্লিপবোর্ডে কপি করার সময় প্রতিক্রিয়া জানান

কোনও অ্যাপ ক্লিপবোর্ডে কন্টেন্ট কপি করলে ব্যবহারকারীরা ভিজ্যুয়াল ফিডব্যাক আশা করেন। অ্যান্ড্রয়েড ১৩ এবং তার পরবর্তী সংস্করণের ব্যবহারকারীদের জন্য এটি স্বয়ংক্রিয়ভাবে করা হয়, তবে পূর্ববর্তী সংস্করণগুলিতে এটি ম্যানুয়ালি প্রয়োগ করতে হবে।

অ্যান্ড্রয়েড ১৩ থেকে শুরু করে, ক্লিপবোর্ডে কন্টেন্ট যোগ করা হলে সিস্টেমটি একটি স্ট্যান্ডার্ড ভিজ্যুয়াল নিশ্চিতকরণ প্রদর্শন করে। নতুন নিশ্চিতকরণটি নিম্নলিখিত কাজগুলি করে:

  • নিশ্চিত করে যে কন্টেন্টটি সফলভাবে কপি করা হয়েছে।
  • কপি করা কন্টেন্টের একটি প্রিভিউ প্রদান করে।

Android 13 ক্লিপবোর্ড বিজ্ঞপ্তি দেখানো একটি অ্যানিমেশন
চিত্র ৩। অ্যান্ড্রয়েড ১৩ এবং তার পরবর্তী সংস্করণে ক্লিপবোর্ডে কন্টেন্ট প্রবেশ করলে UI দেখানো হয়েছে।

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

ডুপ্লিকেট বিজ্ঞপ্তি এড়িয়ে চলুন

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

তথ্যের ডুপ্লিকেট প্রদর্শন এড়াতে, আমরা দৃঢ়ভাবে সুপারিশ করছি যে অ্যান্ড্রয়েড 13 এবং উচ্চতর সংস্করণের জন্য ইন-অ্যাপ কপির পরে প্রদর্শিত টোস্ট বা স্ন্যাকবারগুলি সরিয়ে ফেলা উচিত।

অ্যাপ-মধ্যস্থ কপির পরে স্ন্যাকবার পোস্ট করুন।
চিত্র ৪। অ্যান্ড্রয়েড ১৩-তে যদি আপনি একটি কপি নিশ্চিতকরণ স্ন্যাকবার দেখান, তাহলে ব্যবহারকারী ডুপ্লিকেট বার্তা দেখতে পাবেন।
অ্যাপ-মধ্যস্থ কপির পরে টোস্ট পোস্ট করুন।
চিত্র ৫। যদি আপনি অ্যান্ড্রয়েড ১৩-তে একটি কপি নিশ্চিতকরণ টোস্ট দেখান, তাহলে ব্যবহারকারী ডুপ্লিকেট বার্তা দেখতে পাবেন।

এটি কীভাবে বাস্তবায়ন করবেন তার একটি উদাহরণ এখানে দেওয়া হল:

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() ব্যবহার করে এর টেক্সটটি আপনার নিজস্ব স্টোরেজে কপি করুন, যেমনটি নিম্নলিখিত পদ্ধতিতে বর্ণনা করা হয়েছে:

  1. getSystemService(CLIPBOARD_SERVICE) ব্যবহার করে গ্লোবাল ClipboardManager অবজেক্টটি পান। এছাড়াও, পেস্ট করা টেক্সট ধারণ করার জন্য একটি গ্লোবাল ভেরিয়েবল ঘোষণা করুন:

    কোটলিন

    var clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    var pasteData: String = ""

    জাভা

    ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
    String pasteData = "";
  2. বর্তমান কার্যকলাপে "পেস্ট" বিকল্পটি সক্রিয় বা নিষ্ক্রিয় করতে হবে কিনা তা নির্ধারণ করুন। ক্লিপবোর্ডে একটি ক্লিপ রয়েছে কিনা এবং আপনি ক্লিপ দ্বারা উপস্থাপিত ডেটার ধরণ পরিচালনা করতে পারেন কিনা তা যাচাই করুন:

    কোটলিন

    // 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);
    }
  3. ক্লিপবোর্ড থেকে ডেটা কপি করুন। কোডের এই বিন্দুটি শুধুমাত্র "পেস্ট" মেনু আইটেমটি সক্রিয় থাকলেই পৌঁছানো সম্ভব, তাই আপনি ধরে নিতে পারেন যে ক্লিপবোর্ডে প্লেইন টেক্সট রয়েছে। আপনি এখনও জানেন না যে এতে কোনও টেক্সট স্ট্রিং আছে নাকি প্লেইন টেক্সট নির্দেশ করে এমন একটি 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 টাইপ প্রদানকারীর কাছ থেকে পাওয়া যায় কিনা।

  1. 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";
  2. গ্লোবাল ক্লিপবোর্ডটি পান। এছাড়াও একটি কন্টেন্ট রিজলভার পান যাতে আপনি কন্টেন্ট প্রদানকারী অ্যাক্সেস করতে পারেন:

    কোটলিন

    // 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();
  3. ক্লিপবোর্ড থেকে প্রাথমিক ক্লিপটি পান এবং এর বিষয়বস্তুগুলি 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();
  4. getType(Uri) কল করে URI একটি কন্টেন্ট 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);
  5. কন্টেন্ট প্রোভাইডার অ্যাপ্লিকেশনটি যে 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 অ্যাক্সেস করে। টোস্টটি তখনই প্রদর্শিত হয় যখন আপনার অ্যাপটি প্রথমবারের মতো সেই অ্যাপ থেকে ডেটা অ্যাক্সেস করে।
  • ক্লিপ অবজেক্টের জন্য মেটাডেটা পুনরুদ্ধার করে, যেমন getPrimaryClipDescription() getPrimaryClip() () কল করে।

জটিল তথ্য কপি করার জন্য কন্টেন্ট প্রদানকারী ব্যবহার করুন

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

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

কন্টেন্ট প্রদানকারীতে, অন্তত নিম্নলিখিত পদ্ধতিগুলি ওভাররাইড করুন:

query()
অ্যাপ্লিকেশন পেস্ট করার সময় ধরে নেওয়া হয় যে তারা ক্লিপবোর্ডে রাখা URI ব্যবহার করে এই পদ্ধতি ব্যবহার করে আপনার ডেটা পেতে পারে। কপি করার সুবিধার্থে, এই পদ্ধতিতে একটি বিশেষ "কপি" পাথ সম্বলিত URI সনাক্ত করতে হবে। আপনার অ্যাপ্লিকেশনটি তখন ক্লিপবোর্ডে রাখার জন্য একটি "কপি" URI তৈরি করতে পারে, যেখানে কপি পাথ এবং আপনি যে রেকর্ডটি কপি করতে চান তার একটি পয়েন্টার থাকবে।
getType()
এই পদ্ধতিতে আপনি যে ডেটা কপি করতে চান তার জন্য MIME প্রকারগুলি ফেরত দিতে হবে। newUri() পদ্ধতিটি getType() কল করে MIME প্রকারগুলিকে নতুন ClipData অবজেক্টে রাখে।

জটিল ডেটার জন্য MIME প্রকারগুলি Content providers- এ বর্ণিত হয়েছে।

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

জটিল ডেটা কপি করার জন্য আপনার অ্যাপ্লিকেশনটি কীভাবে সেট আপ করবেন তা নিম্নলিখিত স্নিপেটগুলি দেখায়:

  1. আপনার অ্যাপ্লিকেশনের গ্লোবাল ধ্রুবকগুলিতে, একটি বেস 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";
  2. ব্যবহারকারীরা যে কার্যকলাপ থেকে ডেটা কপি করেন, সেখানে ক্লিপবোর্ডে ডেটা কপি করার জন্য কোড সেট আপ করুন। কপি অনুরোধের প্রতিক্রিয়ায়, ক্লিপবোর্ডে 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);
  3. আপনার কন্টেন্ট প্রোভাইডারের গ্লোবাল স্কোপে, একটি 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);
  4. 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.
        ...
    }
  5. কপি করা ডেটার জন্য উপযুক্ত 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 এর মতো একটি ফাইল বর্ণনাকারী অবজেক্ট ব্যবহার করে তার ডেটাতে অ্যাক্সেস প্রদান করে। পেস্টিং অ্যাপ্লিকেশনটি এই ফাইল বর্ণনাকারী ব্যবহার করে ডেটা স্ট্রিমটি পড়ে।

কোনও প্রোভাইডার থেকে ডেটা স্ট্রিম কপি করার জন্য আপনার অ্যাপ্লিকেশন সেট আপ করতে, এই পদক্ষেপগুলি অনুসরণ করুন:

  1. ক্লিপবোর্ডে যে ডেটা স্ট্রিমটি রাখবেন তার জন্য একটি কন্টেন্ট URI সেট আপ করুন। এটি করার জন্য নিম্নলিখিত বিকল্পগুলির মধ্যে রয়েছে:
    • URI বিভাগে "Encode an identifier" বিভাগে বর্ণিত হিসাবে, URI-তে ডেটা স্ট্রিমের জন্য একটি শনাক্তকারী এনকোড করুন, এবং তারপর আপনার প্রোভাইডারে একটি টেবিল বজায় রাখুন যাতে শনাক্তকারী এবং সংশ্লিষ্ট স্ট্রিমের নাম থাকে।
    • সরাসরি URI তে স্ট্রিমের নাম এনকোড করুন।
    • একটি অনন্য URI ব্যবহার করুন যা সর্বদা প্রদানকারীর কাছ থেকে বর্তমান স্ট্রিম ফেরত দেয়। আপনি যদি এই বিকল্পটি ব্যবহার করেন, তাহলে URI ব্যবহার করে ক্লিপবোর্ডে স্ট্রিমটি কপি করার সময় আপনার প্রদানকারীকে একটি ভিন্ন স্ট্রিম নির্দেশ করার জন্য আপডেট করতে ভুলবেন না।
  2. আপনার প্রস্তাবিত প্রতিটি ধরণের ডেটা স্ট্রিমটির জন্য একটি MIME টাইপ প্রদান করুন। পেস্টিং অ্যাপ্লিকেশনগুলির ক্লিপবোর্ডে ডেটা পেস্ট করতে পারবে কিনা তা নির্ধারণ করার জন্য এই তথ্যের প্রয়োজন।
  3. ContentProvider পদ্ধতিগুলির মধ্যে একটি প্রয়োগ করুন যা একটি স্ট্রিমের জন্য একটি ফাইল বর্ণনাকারী প্রদান করে। যদি আপনি কন্টেন্ট URI-তে শনাক্তকারী এনকোড করেন, তাহলে কোন স্ট্রিমটি খুলবেন তা নির্ধারণ করতে এই পদ্ধতিটি ব্যবহার করুন।
  4. ক্লিপবোর্ডে ডেটা স্ট্রিম কপি করতে, কন্টেন্ট URI তৈরি করুন এবং ক্লিপবোর্ডে রাখুন।

একটি ডেটা স্ট্রিম পেস্ট করার জন্য, একটি অ্যাপ্লিকেশন ক্লিপবোর্ড থেকে ক্লিপটি পায়, URI পায় এবং এটি একটি ContentResolver ফাইল বর্ণনাকারী পদ্ধতিতে কল করার জন্য ব্যবহার করে যা স্ট্রিমটি খোলে। ContentResolver পদ্ধতিটি সংশ্লিষ্ট ContentProvider পদ্ধতিটিকে কল করে, এটিকে কন্টেন্ট URI পাস করে। আপনার সরবরাহকারী ফাইল বর্ণনাকারীটিকে ContentResolver পদ্ধতিতে ফেরত পাঠায়। তারপর পেস্ট করা অ্যাপ্লিকেশনটির স্ট্রিম থেকে ডেটা পড়ার দায়িত্ব থাকে।

নিচের তালিকাটি একটি কন্টেন্ট প্রদানকারীর জন্য সবচেয়ে গুরুত্বপূর্ণ ফাইল বর্ণনাকারী পদ্ধতিগুলি দেখায়। এগুলির প্রতিটিতে একটি সংশ্লিষ্ট ContentResolver পদ্ধতি রয়েছে যার সাথে পদ্ধতির নামের সাথে "Descriptor" স্ট্রিং যুক্ত থাকে। উদাহরণস্বরূপ, openAssetFile() এর ContentResolver অ্যানালগ হল openAssetFileDescriptor()

openTypedAssetFile()

এই পদ্ধতিটি একটি অ্যাসেট ফাইল বর্ণনাকারী প্রদান করে, তবে শুধুমাত্র যদি প্রদত্ত MIME প্রকারটি প্রদানকারী দ্বারা সমর্থিত হয়। কলার - যে অ্যাপ্লিকেশনটি পেস্ট করছে - একটি MIME প্রকার প্যাটার্ন প্রদান করে। অ্যাপ্লিকেশনের কন্টেন্ট প্রদানকারী যা ক্লিপবোর্ডে একটি URI অনুলিপি করে, যদি MIME প্রকারটি প্রদান করতে পারে তবে একটি AssetFileDescriptor ফাইল হ্যান্ডেল প্রদান করে এবং যদি না পারে তবে একটি ব্যতিক্রম প্রদান করে।

এই পদ্ধতিটি ফাইলের উপ-বিভাগ পরিচালনা করে। আপনি এটি ব্যবহার করে কন্টেন্ট প্রদানকারী ক্লিপবোর্ডে কপি করা সম্পদগুলি পড়তে পারেন।

openAssetFile()
এই পদ্ধতিটি openTypedAssetFile() এর একটি সাধারণ রূপ। এটি অনুমোদিত MIME প্রকারের জন্য ফিল্টার করে না, তবে এটি ফাইলের উপ-বিভাগগুলি পড়তে পারে।
openFile()
এটি openAssetFile() এর একটি সাধারণ রূপ। এটি ফাইলের উপ-বিভাগগুলি পড়তে পারে না।

আপনি ঐচ্ছিকভাবে আপনার ফাইল বর্ণনাকারী পদ্ধতির সাথে openPipeHelper() পদ্ধতি ব্যবহার করতে পারেন। এটি পেস্টিং অ্যাপ্লিকেশনটিকে একটি পাইপ ব্যবহার করে একটি ব্যাকগ্রাউন্ড থ্রেডে স্ট্রিম ডেটা পড়তে দেয়। এই পদ্ধতিটি ব্যবহার করতে, ContentProvider.PipeDataWriter ইন্টারফেসটি প্রয়োগ করুন।

কার্যকর কপি এবং পেস্ট কার্যকারিতা ডিজাইন করুন

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

  • যেকোনো সময়, ক্লিপবোর্ডে শুধুমাত্র একটি ক্লিপ থাকে। সিস্টেমের যেকোনো অ্যাপ্লিকেশন দ্বারা একটি নতুন কপি অপারেশন পূর্ববর্তী ক্লিপটিকে ওভাররাইট করে। যেহেতু ব্যবহারকারী আপনার অ্যাপ্লিকেশন থেকে দূরে সরে যেতে পারে এবং ফিরে আসার আগে কপি করতে পারে, তাই আপনি ধরে নিতে পারবেন না যে ক্লিপবোর্ডে সেই ক্লিপটি রয়েছে যা ব্যবহারকারী আপনার অ্যাপ্লিকেশনে পূর্বে কপি করেছিলেন।
  • প্রতি ক্লিপে একাধিক ClipData.Item অবজেক্টের উদ্দেশ্য হল একাধিক নির্বাচনের কপি এবং পেস্টিং সমর্থন করা, একটি একক নির্বাচনের বিভিন্ন ধরণের রেফারেন্সের পরিবর্তে। আপনি সাধারণত চান যে একটি ক্লিপে থাকা সমস্ত ClipData.Item অবজেক্টের ফর্ম একই হোক। অর্থাৎ, এগুলি অবশ্যই সরল পাঠ্য, কন্টেন্ট URI, অথবা Intent হতে হবে এবং মিশ্রিত হবে না।
  • যখন আপনি ডেটা প্রদান করেন, তখন আপনি বিভিন্ন MIME উপস্থাপনা অফার করতে পারেন। ClipDescription এ আপনার সমর্থন করা MIME প্রকারগুলি যোগ করুন, এবং তারপর আপনার কন্টেন্ট প্রদানকারীতে MIME প্রকারগুলি প্রয়োগ করুন।
  • যখন আপনি ক্লিপবোর্ড থেকে ডেটা পান, তখন আপনার অ্যাপ্লিকেশনটি উপলব্ধ MIME প্রকারগুলি পরীক্ষা করার জন্য এবং তারপর কোনটি ব্যবহার করতে হবে তা নির্ধারণ করার জন্য দায়ী। এমনকি যদি ক্লিপবোর্ডে একটি ক্লিপ থাকে এবং ব্যবহারকারী পেস্টের অনুরোধ করে, আপনার অ্যাপ্লিকেশনটিকে পেস্ট করার প্রয়োজন হয় না। MIME প্রকারটি সামঞ্জস্যপূর্ণ হলে পেস্ট করুন। আপনি coerceToText() ব্যবহার করে ক্লিপবোর্ডের ডেটা টেক্সটে জোর করতে পারেন। যদি আপনার অ্যাপ্লিকেশনটি উপলব্ধ একাধিক MIME প্রকার সমর্থন করে, তাহলে আপনি ব্যবহারকারীকে কোনটি ব্যবহার করবেন তা বেছে নিতে দিতে পারেন।