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

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

যেহেতু ফ্রেমওয়ার্কের একটি অংশ সামগ্রী সরবরাহকারী ব্যবহার করে, তাই এই নথিটি Android সামগ্রী প্রদানকারী API এর সাথে কিছু পরিচিতি অনুমান করে, যা বিষয়বস্তু প্রদানকারীতে বর্ণিত হয়েছে৷

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

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

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

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

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

পাঠ্য
একটি টেক্সট স্ট্রিং। স্ট্রিংটি সরাসরি ক্লিপ অবজেক্টে রাখুন, যা আপনি তারপর ক্লিপবোর্ডে রাখবেন। স্ট্রিংটি পেস্ট করতে, ক্লিপবোর্ড থেকে ক্লিপ অবজেক্টটি পান এবং স্ট্রিংটি আপনার অ্যাপ্লিকেশনের স্টোরেজে অনুলিপি করুন।
ইউআরআই
একটি Uri অবজেক্ট যা URI-এর যেকোনো রূপকে প্রতিনিধিত্ব করে। এটি মূলত একটি বিষয়বস্তু প্রদানকারীর কাছ থেকে জটিল ডেটা অনুলিপি করার জন্য। ডেটা কপি করতে, একটি Uri অবজেক্টকে একটি ক্লিপ অবজেক্টে রাখুন এবং ক্লিপ অবজেক্টটিকে ক্লিপবোর্ডে রাখুন। ডেটা পেস্ট করতে, ক্লিপ অবজেক্ট পান, 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 রাখে। যে অ্যাপ্লিকেশনগুলি ডেটা পেস্ট করতে চায় তারা ক্লিপবোর্ড থেকে ইউআরআই পায় এবং সামগ্রী সরবরাহকারী বা অন্যান্য ডেটা উত্স অ্যাক্সেস করতে এবং ডেটা পুনরুদ্ধার করতে এটি ব্যবহার করে৷
অভিপ্রায়
একটি Intent । এই ডেটা টাইপ আপনাকে ক্লিপবোর্ডে একটি অ্যাপ্লিকেশন শর্টকাট কপি করতে দেয়। ব্যবহারকারীরা পরবর্তীতে ব্যবহারের জন্য তাদের অ্যাপ্লিকেশনে শর্টকাট পেস্ট করতে পারেন।

আপনি একটি ক্লিপে একাধিক ClipData.Item বস্তু যোগ করতে পারেন। এটি ব্যবহারকারীদের একক ক্লিপ হিসাবে একাধিক নির্বাচন কপি এবং পেস্ট করতে দেয়। উদাহরণস্বরূপ, যদি আপনার একটি তালিকা উইজেট থাকে যা ব্যবহারকারীকে একবারে একাধিক আইটেম নির্বাচন করতে দেয়, আপনি একবারে সমস্ত আইটেম ক্লিপবোর্ডে অনুলিপি করতে পারেন। এটি করার জন্য, প্রতিটি তালিকা আইটেমের জন্য একটি পৃথক ClipData.Item তৈরি করুন এবং তারপর ClipData বস্তুতে ClipData.Item অবজেক্ট যোগ করুন।

ক্লিপডেটা সুবিধার পদ্ধতি

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: — পদ্ধতিটি সামগ্রী প্রদানকারীর কাছ থেকে উপলব্ধ MIME প্রকারগুলি পুনরুদ্ধার করতে resolver প্রদত্ত ContentResolver অবজেক্ট ব্যবহার করে। এটি তারপর 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() যদি শূন্য না হয়- coerceToText() এটিকে একটি বিষয়বস্তু URI হিসেবে ব্যবহার করার চেষ্টা করে।
  • যদি URI একটি বিষয়বস্তু URI হয় এবং প্রদানকারী একটি পাঠ্য স্ট্রীম ফেরত দিতে পারে, coerceToText() একটি পাঠ্য স্ট্রীম প্রদান করে।
  • যদি URI একটি বিষয়বস্তু URI হয় কিন্তু প্রদানকারী একটি পাঠ্য স্ট্রীম অফার না করে, coerceToText() URI-এর একটি উপস্থাপনা প্রদান করে। উপস্থাপনাটি Uri.toString() দ্বারা প্রত্যাবর্তিত হিসাবে একই।
  • যদি URI একটি বিষয়বস্তু URI না হয়, coerceToText() URI-এর একটি উপস্থাপনা প্রদান করে। উপস্থাপনাটি Uri.toString() দ্বারা প্রত্যাবর্তিত হিসাবে একই।
অভিপ্রায়
যদি ClipData.Item একটি Intent হয়—অর্থাৎ, getIntent() যদি শূন্য না হয়— coerceToText() এটিকে একটি ইন্টেন্ট URI-তে রূপান্তর করে এবং ফেরত দেয়। উপস্থাপনাটি Intent.toUri(URI_INTENT_SCHEME) দ্বারা প্রত্যাবর্তনের মতই।

ক্লিপবোর্ড ফ্রেমওয়ার্ক চিত্র 2-এ সংক্ষিপ্ত করা হয়েছে। ডেটা কপি করতে, একটি অ্যাপ্লিকেশন ClipboardManager গ্লোবাল ক্লিপবোর্ডে একটি ClipData অবজেক্ট রাখে। ClipData এক বা একাধিক ClipData.Item অবজেক্ট এবং একটি ClipDescription অবজেক্ট থাকে। ডেটা পেস্ট করতে, একটি অ্যাপ্লিকেশন ClipData পায়, ClipDescription থেকে তার MIME প্রকার পায় এবং ClipData.Item থেকে বা ClipData.Item দ্বারা উল্লেখিত সামগ্রী প্রদানকারীর কাছ থেকে ডেটা পায়।

কপি এবং পেস্ট ফ্রেমওয়ার্কের একটি ব্লক ডায়াগ্রাম দেখানো একটি চিত্র
চিত্র 2। অ্যান্ড্রয়েড ক্লিপবোর্ড ফ্রেমওয়ার্ক।

ক্লিপবোর্ডে কপি করুন

ক্লিপবোর্ডে ডেটা অনুলিপি করতে, গ্লোবাল ClipboardManager অবজেক্টের একটি হ্যান্ডেল পান, একটি ClipData অবজেক্ট তৈরি করুন এবং এতে একটি ClipDescription এবং এক বা একাধিক ClipData.Item অবজেক্ট যোগ করুন। তারপর, ClipboardManager অবজেক্টে সমাপ্ত ClipData অবজেক্ট যোগ করুন। এটি নিম্নলিখিত পদ্ধতিতে আরও বর্ণনা করা হয়েছে:

  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);
    

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

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

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

  • কনফার্ম করে কন্টেন্ট সফলভাবে কপি করা হয়েছে।
  • অনুলিপি করা বিষয়বস্তুর একটি পূর্বরূপ প্রদান করে।

Android 13 ক্লিপবোর্ড বিজ্ঞপ্তি দেখানো একটি অ্যানিমেশন
চিত্র 3. Android 13 এবং তার পরের ক্লিপবোর্ডে কন্টেন্ট প্রবেশ করলে UI দেখানো হয়।

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

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

Android 12L (API লেভেল 32) এবং তার নিচে, আমরা ব্যবহারকারীদের সতর্ক করার পরামর্শ দিই যখন তারা কপি করার পরে, Toast বা Snackbar মতো উইজেট ব্যবহার করে ভিজ্যুয়াল, ইন-অ্যাপ প্রতিক্রিয়া জারি করে সফলভাবে কপি করে।

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

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

সংবেদনশীল বিষয়বস্তু পতাকাঙ্কিত না করেই টেক্সট প্রিভিউ কপি করা হয়েছে
চিত্র 6. একটি সংবেদনশীল বিষয়বস্তুর পতাকা ছাড়াই অনুলিপি করা পাঠ্যের পূর্বরূপ৷
সংবেদনশীল কন্টেন্ট ফ্ল্যাগিং টেক্সট প্রিভিউ কপি করা হয়েছে।
চিত্র 7. একটি সংবেদনশীল বিষয়বস্তুর পতাকা সহ অনুলিপি করা পাঠ্যের পূর্বরূপ৷

সংবেদনশীল বিষয়বস্তু ফ্ল্যাগ করতে, 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 কোনো বৈধ বিষয়বস্তু প্রদানকারীকে নির্দেশ না করলে এই পদ্ধতিটি শূন্য হয়ে যায়।

    কোটলিন

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

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

Android 12 (API লেভেল 31) এবং তার উপরে, আপনার অ্যাপ getPrimaryClip() কল করলে সিস্টেম সাধারণত একটি টোস্ট বার্তা দেখায়। বার্তার ভিতরের পাঠ্যটিতে নিম্নলিখিত বিন্যাস রয়েছে:

APP pasted from your clipboard

যখন আপনার অ্যাপ নিম্নলিখিতগুলির মধ্যে একটি করে তখন সিস্টেমটি একটি টোস্ট বার্তা দেখায় না:

  • আপনার নিজের অ্যাপ থেকে ClipData অ্যাক্সেস করে।
  • একটি নির্দিষ্ট অ্যাপ থেকে বারবার ClipData অ্যাক্সেস করে। টোস্টটি তখনই প্রদর্শিত হয় যখন আপনার অ্যাপটি সেই অ্যাপ থেকে প্রথমবারের মতো ডেটা অ্যাক্সেস করে।
  • ক্লিপ অবজেক্টের জন্য মেটাডেটা পুনরুদ্ধার করে, যেমন getPrimaryClip() এর পরিবর্তে getPrimaryClipDescription() ) কল করে।

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

বিষয়বস্তু প্রদানকারীরা জটিল ডেটা যেমন ডাটাবেস রেকর্ড বা ফাইল স্ট্রীম অনুলিপি করতে সমর্থন করে। ডেটা অনুলিপি করতে, ক্লিপবোর্ডে একটি বিষয়বস্তু 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"

ইউআরআই অনুলিপি করার জন্য আপনি অন্য পথ যোগ করতে পারেন:

"content://com.example.contacts/copying"

তারপর আপনি প্যাটার্ন-ম্যাচিং দ্বারা একটি "অনুলিপি" URI সনাক্ত করতে পারেন এবং কপি এবং পেস্ট করার জন্য নির্দিষ্ট কোড দিয়ে এটি পরিচালনা করতে পারেন।

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

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

ডেটা স্ট্রাকচার কপি করুন

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

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

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

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

জটিল ডেটার জন্য MIME প্রকারগুলি বিষয়বস্তু প্রদানকারীগুলিতে বর্ণনা করা হয়েছে৷

আপনার অন্য কোন সামগ্রী প্রদানকারী পদ্ধতির প্রয়োজন নেই, যেমন 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);
        ...
        }
    }
    

একটি বিষয়বস্তু URI বিভাগ থেকে পেস্ট ডেটা বর্ণনা করে যে কীভাবে ক্লিপবোর্ড থেকে একটি সামগ্রী URI পেতে হয় এবং ডেটা পেতে এবং পেস্ট করতে এটি ব্যবহার করতে হয়।

ডেটা স্ট্রীম কপি করুন

আপনি স্ট্রিম হিসাবে প্রচুর পরিমাণে পাঠ্য এবং বাইনারি ডেটা কপি এবং পেস্ট করতে পারেন। ডেটাতে নিম্নলিখিতগুলির মতো ফর্ম থাকতে পারে:

  • প্রকৃত ডিভাইসে সঞ্চিত ফাইল
  • সকেট থেকে প্রবাহ
  • একটি প্রদানকারীর অন্তর্নিহিত ডাটাবেস সিস্টেমে প্রচুর পরিমাণে ডেটা সংরক্ষিত

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

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

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

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

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

openTypedAssetFile()

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

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

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

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

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

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

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