کپی کردن و جای‌گذاری

امتحان کردن روش Compose
Jetpack Compose جعبه‌ابزار واسط کاربر توصیه‌شده برای Android است. با نحوه استفاده از کپی و جای‌گذاری در Compose آشنا شوید.

Android چارچوب قدرتمندی مبتنی بر بریده‌دان برای کپی و جای‌گذاری ارائه می‌دهد. این کلاس از انواع داده‌های ساده و پیچیده، ازجمله رشته‌های نوشتاری، ساختارهای داده پیچیده، داده‌های جریانی نوشتاری و دودویی، و دارایی‌های برنامه پشتیبانی می‌کند. داده‌های نوشتاری ساده مستقیماً در بریده‌دان ذخیره می‌شوند، درحالی‌که داده‌های پیچیده به‌عنوان مرجعی ذخیره می‌شوند که برنامه جای‌گذاری با ارائه‌دهنده محتوا حل می‌کند. کپی و جای‌گذاری هم در داخل برنامه و هم بین برنامه‌هایی که چارچوب را پیاده‌سازی می‌کنند کار می‌کند.

ازآنجایی‌که بخشی از چارچوب از ارائه‌دهندگان محتوا استفاده می‌کند، این سند فرض می‌کند که با Android Content Provider API آشنایی دارید، که در ارائه‌دهندگان محتوا شرح داده شده است.

کاربران انتظار دارند هنگام کپی کردن محتوا در بریده‌دان بازخورد دریافت کنند، بنابراین علاوه‌بر چارچوبی که کپی و جای‌گذاری را تقویت می‌کند، Android در Android 13 (سطح API‏ ۳۳) و بالاتر، یک میانای کاربری پیش‌فرض به کاربران نشان می‌دهد. به‌دلیل این ویژگی، خطر اعلان تکراری وجود دارد. می‌توانید درباره این مورد خاص در بخش اجتناب از اعلان‌های تکراری بیشتر بدانید.

پویانمایی‌ای که اعلان بریده‌دان Android 13 را نشان می‌دهد
شکل ۱. رابط کاربری‌ای که وقتی محتوا وارد بریده‌دان می‌شود در Android نسخه ۱۳ و بالاتر نشان داده می‌شود.

در Android 12L (سطح میانای برنامه‌سازی کاربردی ۳۲) و نسخه‌های پایین‌تر، هنگام کپی کردن، به‌صورت دستی به کاربران بازخورد ارائه دهید. توصیه‌های مربوط به این مورد را در این سند ببینید.

چارچوب بریده‌دان

وقتی از چارچوب کلیپ‌بورد استفاده می‌کنید، داده‌ها را در شیء کلیپ قرار دهید و سپس شیء کلیپ را در کلیپ‌بورد سراسری سیستم قرار دهید. شیء کلیپ می‌تواند یکی از این سه شکل را داشته باشد:

نوشتار
رشته نوشتاری. رشته را مستقیماً در شیء کلیپ قرار دهید، سپس آن را در کلیپ‌بورد قرار دهید. برای جای‌گذاری رشته، شیء کلیپ را از بریده‌دان دریافت کنید و رشته را در فضای ذخیره‌سازی برنامه‌تان کپی کنید.
URI
شیء Uri که نشان‌دهنده هر شکلی از URI است. این عمدتاً برای کپی کردن داده‌های پیچیده از ارائه‌دهنده محتوا است. برای کپی کردن داده‌ها، شیء Uri را در شیء کلیپ قرار دهید و شیء کلیپ را در بریده‌دان قرار دهید. برای جای‌گذاری داده‌ها، شیء کلیپ را دریافت کنید، شیء Uri را دریافت کنید، آن را به منبع داده‌ای مانند ارائه‌دهنده محتوا تبدیل کنید، و داده‌ها را از منبع به فضای ذخیره‌سازی برنامه‌تان کپی کنید.
قصد
یک Intent. این از کپی کردن میان‌برهای برنامه پشتیبانی می‌کند. برای کپی کردن داده‌ها، Intent ایجاد کنید، آن را در شیء کلیپ قرار دهید، و شیء کلیپ را در بریده‌دان قرار دهید. برای جای‌گذاری داده‌ها، شیء کلیپ را دریافت کنید و سپس شیء Intent را در ناحیه حافظه برنامه‌تان کپی کنید.

کلیپ‌بورد در هر زمان فقط یک شیء کلیپ را نگه می‌دارد. وقتی برنامه‌ای شیء کلیپ را در کلیپ‌بورد قرار می‌دهد، شیء کلیپ قبلی ناپدید می‌شود.

اگر می‌خواهید به کاربران اجازه دهید داده‌ها را در برنامه‌تان جای‌گذاری کنند، لازم نیست همه انواع داده‌ها را مدیریت کنید. می‌توانید داده‌های موجود در بریده‌دان را قبل‌از اینکه به کاربران گزینه جای‌گذاری آن را بدهید بررسی کنید. علاوه‌بر داشتن فرم داده خاص، شیء کلیپ حاوی فراداده‌ای است که به شما می‌گوید چه نوع MIME دردسترس است. این فراداده به شما کمک می‌کند تصمیم بگیرید که آیا برنامه‌تان می‌تواند کار مفیدی با داده‌های بریده‌دان انجام دهد یا نه. برای مثال، اگر برنامه‌ای دارید که عمدتاً نوشتار را مدیریت می‌کند، ممکن است بخواهید از اشیای کلیپ که حاوی URI یا هدف هستند صرف‌نظر کنید.

همچنین ممکن است بخواهید به کاربران اجازه دهید نوشتار را بدون توجه به شکل داده‌ها در بریده‌دان جای‌گذاری کنند. برای انجام این کار، داده‌های بریده‌دان را به‌اجبار به نمایش نوشتاری تبدیل کنید و سپس این نوشتار را جای‌گذاری کنید. این موضوع در بخش تبدیل اجباری بریده‌دان به نوشتار شرح داده شده است.

کلاس‌های بریده‌دان

این بخش کلاس‌های استفاده‌شده توسط چارچوب کلیپ‌بورد را شرح می‌دهد.

ClipboardManager

حافظه موقت سیستم Android با کلاس سراسری ClipboardManager نشان داده می‌شود. این کلاس را مستقیماً نمونه‌سازی نکنید. به‌جای آن، با فراخوانی getSystemService(CLIPBOARD_SERVICE)، مرجعی برای آن دریافت کنید.

ClipData،‏ ClipData.Item، و ClipDescription

برای افزودن داده به بریده‌دان، یک شیء ClipData ایجاد کنید که حاوی شرحی از داده‌ها و خود داده‌ها باشد. کلیپ‌بورد در هر زمان فقط یک ClipData را نگه می‌دارد. ClipData حاوی شیء ClipDescription و یک یا چند شیء ClipData.Item است.

یک شیء ClipDescription حاوی فراداده درباره کلیپ است. به‌ویژه، این شیء حاوی آرایه‌ای از انواع MIME دردسترس برای داده‌های کلیپ است. علاوه‌براین، در Android 12 (سطح میانای برنامه‌سازی کاربردی ۳۱) و بالاتر، فراداده شامل اطلاعاتی درباره اینکه آیا شیء حاوی نوشتار سبک‌دار است یا نه و درباره نوع نوشتار در شیء می‌شود. وقتی کلیپی را در بریده‌دان قرار می‌دهید، این اطلاعات برای برنامه‌های جای‌گذاری دردسترس است، که می‌توانند بررسی کنند آیا می‌توانند داده‌های کلیپ را مدیریت کنند یا نه.

شیء ClipData.Item حاوی نوشتار، URI، یا داده‌های هدف است:

نوشتار
A CharSequence.
URI
A Uri. این معمولاً حاوی URI ارائه‌دهنده محتوا است، اگرچه هر URI مجاز است. برنامه‌ای که داده‌ها را ارائه می‌دهد، شناسه منبع یکسان را در بریده‌دان قرار می‌دهد. برنامه‌هایی که می‌خواهند داده‌ها را جای‌گذاری کنند، شناسه منبع یکسان را از بریده‌دان دریافت می‌کنند و از آن برای دسترسی به ارائه‌دهنده محتوا یا منبع داده دیگر و بازیابی داده‌ها استفاده می‌کنند.
قصد
یک Intent. این نوع داده به شما امکان می‌دهد میان‌بر برنامه را در بریده‌دان کپی کنید. سپس کاربران می‌توانند میان‌بر را در برنامه‌هایشان جای‌گذاری کنند تا بعداً از آن استفاده کنند.

می‌توانید بیش‌از یک شیء ClipData.Item به کلیپ اضافه کنید. این کار به کاربران اجازه می‌دهد چندین انتخاب را به‌عنوان یک کلیپ کپی و جای‌گذاری کنند. برای مثال، اگر ابزاره فهرستی دارید که به کاربر اجازه می‌دهد بیش‌از یک مورد را در یک زمان انتخاب کند، می‌توانید همه موارد را به‌طور هم‌زمان در بریده‌دان کپی کنید. برای انجام این کار، برای هر مورد فهرست یک ClipData.Item جداگانه ایجاد کنید و سپس اشیاء ClipData.Item را به شیء ClipData اضافه کنید.

روش‌های راحتی ClipData

کلاس ClipData روش‌های راحتی ثابتی برای ایجاد شیء ClipData با یک شیء ClipData.Item و یک شیء ClipDescription ساده ارائه می‌دهد:

newPlainText(label, text)
یک شیء ClipData برمی‌گرداند که شیء ClipData.Item تکی آن حاوی یک رشته نوشتاری است. برچسب شیء ClipDescription روی label تنظیم شده است. نوع MIME تکی در ClipDescription MIMETYPE_TEXT_PLAIN است.

از newPlainText() برای ایجاد کلیپ از رشته نوشتاری استفاده کنید.

newUri(resolver, label, URI)
یک شیء ClipData برمی‌گرداند که شیء ClipData.Item تکی آن حاوی یک URI است. برچسب شیء ClipDescription روی label تنظیم شده است. اگر URI شناسه منبع یکسان محتوا باشد—یعنی اگر Uri.getScheme() content: را برگرداند—این روش از شیء ContentResolver ارائه‌شده در resolver برای بازیابی انواع MIME دردسترس از ارائه‌دهنده محتوا استفاده می‌کند. سپس آن‌ها را در ClipDescription ذخیره می‌کند. برای شناسه منبع یکسانی که شناسه منبع یکسان content: نیست، این روش نوع MIME را روی MIMETYPE_TEXT_URILIST تنظیم می‌کند.

از newUri() برای ایجاد کلیپ از URI استفاده کنید—به‌ویژه content: URI.

newIntent(label, intent)
شیء ClipData را برمی‌گرداند که شیء ClipData.Item تکی آن حاوی Intent است. برچسب شیء ClipDescription روی label تنظیم شده است. نوع MIME روی MIMETYPE_TEXT_INTENT تنظیم شده است.

از newIntent() برای ایجاد کلیپ از شیء Intent استفاده کنید.

تبدیل اجباری داده‌های بریده‌دان به نوشتار

حتی اگر برنامه شما فقط نوشتار را مدیریت می‌کند، می‌توانید داده‌های غیرنوشتاری را از بریده‌دان کپی کنید با تبدیل آن با ClipData.Item.coerceToText() روش.

این روش داده‌های موجود در ClipData.Item را به نوشتار تبدیل می‌کند و CharSequence را برمی‌گرداند. مقداری که ClipData.Item.coerceToText() برمی‌گرداند براساس شکل داده‌ها در ClipData.Item است:

نوشتار
اگر ClipData.Item نوشتار باشد—یعنی اگر getText() تهی نباشد—coerceToText()‎ نوشتار را برمی‌گرداند.
URI
اگر ClipData.Item یک URI باشد—یعنی اگر getUri() تهی نباشد—coerceToText() سعی می‌کند از آن به‌عنوان URI محتوا استفاده کند.
  • اگر URI شناسه منبع یکسان محتوا باشد و ارائه‌دهنده بتواند جریان نوشتاری برگرداند، coerceToText() جریان نوشتاری برمی‌گرداند.
  • اگر شناسه منبع یکسان از نوع شناسه منبع یکسان محتوا باشد اما ارائه‌دهنده جریان نوشتاری ارائه ندهد، coerceToText() نمایشی از شناسه منبع یکسان را برمی‌گرداند. نمایش همانند چیزی است که توسط Uri.toString() برگردانده شده است.
  • اگر URI شناسه منبع یکسان محتوا نباشد، coerceToText() نمایشی از URI را برمی‌گرداند. این نمایش همان نمایشی است که توسط Uri.toString() برگردانده شده است.
قصد
اگر ClipData.Item یک Intent باشد—یعنی اگر getIntent() تهی نباشد—coerceToText() آن را به URI هدف تبدیل می‌کند و برمی‌گرداند. این نمایش همان نمایشی است که توسط Intent.toUri(URI_INTENT_SCHEME) برگردانده شده است.

چارچوب بریده‌دان در شکل ۲ خلاصه شده است. برای کپی کردن داده‌ها، برنامه یک شیء ClipData را در بریده‌دان سراسری ClipboardManager قرار می‌دهد. ClipData حاوی یک یا چند شیء ClipData.Item و یک شیء ClipDescription است. برای جای‌گذاری داده‌ها، برنامه ClipData را دریافت می‌کند، نوع MIME آن را از ClipDescription دریافت می‌کند، و داده‌ها را از ClipData.Item یا از ارائه‌دهنده محتوایی که توسط ClipData.Item ارجاع داده شده است دریافت می‌کند.

تصویری که نمودار بلوکی چارچوب کپی و جای‌گذاری را نشان می‌دهد
شکل ۲. چارچوب بریده‌دان Android.

کپی کردن در بریده‌دان

برای کپی کردن داده‌ها در بریده‌دان، دستگیره‌ای برای شیء سراسری ClipboardManager دریافت کنید، شیء ClipData ایجاد کنید، و ClipDescription و یک یا چند شیء ClipData.Item به آن اضافه کنید. سپس، شیء ClipData تکمیل‌شده را به شیء ClipboardManager اضافه کنید. این موضوع در روال زیر بیشتر توضیح داده شده است:

  1. اگر داده‌ها را بااستفاده از شناسه منبع یکسان محتوا کپی می‌کنید، ارائه‌دهنده محتوا راه‌اندازی کنید.
  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 پوشش داده شده است.

      کاتلین

      // 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 و بالاتر انجام می‌شود، اما در نسخه‌های قبلی باید به‌صورت دستی پیاده‌سازی شود.

از Android 13 به بعد، وقتی محتوایی به بریده‌دان اضافه می‌شود، سیستم تأیید دیداری استانداردی را نمایش می‌دهد. تأییدیه جدید کارهای زیر را انجام می‌دهد:

  • تأیید می‌کند که محتوا با موفقیت کپی شده است.
  • پیش‌نمایشی از محتوای کپی‌شده ارائه می‌دهد.

پویانمایی‌ای که اعلان بریده‌دان Android 13 را نشان می‌دهد
شکل ۳. رابط کاربری‌ای که وقتی محتوا وارد بریده‌دان می‌شود در Android نسخه ۱۳ و بالاتر نشان داده می‌شود.

در Android 12L (سطح API‏ ۳۲) و نسخه‌های پایین‌تر، ممکن است کاربران مطمئن نباشند که محتوا را باموفقیت کپی کرده‌اند یا چه چیزی را کپی کرده‌اند. این ویژگی اعلان‌های مختلفی را که برنامه‌ها پس‌از کپی کردن نشان می‌دهند استاندارد می‌کند و به کاربران امکان می‌دهد کنترل بیشتری روی بریده‌دان داشته باشند.

جلوگیری از اعلان‌های تکراری

در Android 12L (سطح API‏ ۳۲) و پایین‌تر، توصیه می‌کنیم وقتی کاربران با موفقیت کپی می‌کنند، با ارائه بازخورد تصویری درون‌برنامه، بااستفاده از ابزارهایی مانند Toast یا Snackbar، پس‌از کپی کردن، به آن‌ها هشدار دهید.

برای جلوگیری از نمایش تکراری اطلاعات، اکیداً توصیه می‌کنیم برای Android 13 و نسخه‌های بالاتر، پیام‌های موقت یا نوارهای میان‌وعده را که پس‌از کپی درون‌برنامه نشان داده می‌شوند بردارید.

پس‌از کپی درون‌برنامه، نوار میان‌وعده را پست کنید.
شکل ۴. اگر در Android 13 نوار میان‌وعده تأیید کپی را نشان دهید، کاربر پیام‌های تکراری می‌بیند.
Post toast after an in-app copy.
شکل ۵. اگر در 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()، پرچمی به ClipDescription در ClipData اضافه کنید. افزودن این پرچم از نمایش محتوای حساس در تأیید تصویری محتوای کپی‌شده در Android نسخه ۱۳ و بالاتر جلوگیری می‌کند.

پیش‌نمایش نوشتار کپی‌شده بدون پرچم‌گذاری محتوای حساس
شکل ۶. پیش‌نمایش نوشتار کپی‌شده بدون پرچم محتوای حساس.
پیش‌نمایش نوشتار کپی‌شده که محتوای حساس را پرچم‌گذاری می‌کند.
شکل ۷. پیش‌نمایش نوشتار کپی‌شده با پرچم محتوای حساس.

برای پرچم‌گذاری محتوای حساس، یک مقدار بولی اضافی به ClipDescription اضافه کنید. همه برنامه‌ها باید این کار را انجام دهند، صرف‌نظر از سطح میانای برنامه‌سازی کاربردی هدف.

// 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. دریافت شیء سراسری ClipboardManager بااستفاده از getSystemService(CLIPBOARD_SERVICE). همچنین، یک متغیر سراسری را برای نگهداری نوشتار جای‌گذاری‌شده اعلام کنید:

    کاتلین

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

جای‌گذاری داده از شناسه منبع یکسان محتوا

اگر شیء ClipData.Item حاوی شناسه منبع یکسان محتوا باشد و تشخیص دهید که می‌توانید یکی از انواع MIME آن را مدیریت کنید، یک ContentResolver ایجاد کنید و روش ارائه‌دهنده محتوای مناسب را برای بازیابی داده‌ها فراخوانی کنید.

روش زیر نحوه دریافت داده از ارائه‌دهنده محتوا را براساس شناسه منبع یکسان محتوا در بریده‌دان شرح می‌دهد. این روش بررسی می‌کند که آیا نوع 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 به ارائه‌دهنده محتوای معتبری اشاره نکند، این روش مقدار تهی را برمی‌گرداند.

    کاتلین

        // 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 نسخه ۱۲ (سطح میانای برنامه‌سازی کاربردی ۳۱) و بالاتر، وقتی برنامه‌تان getPrimaryClip() را فراخوانی می‌کند، سیستم معمولاً پیام زودگذری نشان می‌دهد. نوشتار داخل پیام حاوی قالب زیر است:

APP pasted from your clipboard

وقتی برنامه‌تان یکی از کارهای زیر را انجام می‌دهد، سیستم پیام موقتی نشان نمی‌دهد:

  • به ClipData از برنامه خودتان دسترسی دارد.
  • به‌طور مکرر از برنامه‌ای خاص به ClipData دسترسی پیدا می‌کند. این اعلان فقط زمانی ظاهر می‌شود که برنامه شما برای اولین‌بار از آن برنامه به داده‌ها دسترسی پیدا کند.
  • فراداده را برای شیء کلیپ بازیابی می‌کند، مثلاً با فراخوانی getPrimaryClipDescription() به‌جای getPrimaryClip().

استفاده از ارائه‌دهندگان محتوا برای کپی کردن داده‌های پیچیده

ارائه‌دهندگان محتوا از کپی کردن داده‌های پیچیده مانند سوابق پایگاه داده یا جریان‌های فایل پشتیبانی می‌کنند. برای کپی کردن داده‌ها، شناسه منبع یکسان محتوا را در بریده‌دان قرار دهید. سپس برنامه‌های جای‌گذاری این URI را از کلیپ‌بورد دریافت می‌کنند و از آن برای بازیابی داده‌های پایگاه داده یا توصیف‌کننده‌های جریان فایل استفاده می‌کنند.

ازآنجایی‌که برنامه جای‌گذاری فقط شناسه منبع یکسان محتوا را برای داده‌های شما دارد، باید بداند کدام بخش از داده‌ها را بازیابی کند. می‌توانید این اطلاعات را با کدگذاری شناسه‌ای برای داده‌ها در خود URI ارائه دهید، یا می‌توانید URI منحصربه‌فردی ارائه دهید که داده‌هایی را که می‌خواهید کپی کنید برمی‌گرداند. انتخاب تکنیک به سازماندهی داده‌های شما بستگی دارد.

بخش‌های زیر نحوه راه‌اندازی URI، ارائه داده‌های پیچیده، و ارائه جریان‌های فایل را شرح می‌دهد. در این توضیحات فرض شده است که با اصول کلی طراحی ارائه‌دهنده محتوا آشنا هستید.

کدگذاری شناسه در URI

یک روش مفید برای کپی کردن داده‌ها در بریده‌دان با URI، کدگذاری یک شناسه برای داده‌ها در خود URI است. سپس ارائه‌دهنده محتوای شما می‌تواند شناسه را از URI دریافت کند و از آن برای بازیابی داده‌ها استفاده کند. برنامه جای‌گذاری‌کننده لازم نیست بداند که شناسه وجود دارد. فقط باید «مرجع» شما (URI به‌علاوه شناسه) را از بریده‌دان دریافت کند، آن را به ارائه‌دهنده محتوای شما بدهد، و داده‌ها را برگرداند.

معمولاً شناسه‌ای را با الحاق آن به انتهای شناسه منبع یکسان محتوا، روی آن کدگذاری می‌کنید. برای مثال، فرض کنید شناسه URI ارائه‌دهنده را به‌صورت رشته زیر تعریف می‌کنید:

"content://com.example.contacts"

اگر می‌خواهید نامی را در این URI کدگذاری کنید، از تکه‌کد زیر استفاده کنید:

کاتلین

val uriString = "content://com.example.contacts/Smith"

// uriString now contains content://com.example.contacts/Smith.

// Generates a uri object from the string representation.
val copyUri = Uri.parse(uriString)

جاوا

String uriString = "content://com.example.contacts" + "/" + "Smith";

// uriString now contains content://com.example.contacts/Smith.

// Generates a uri object from the string representation.
Uri copyUri = Uri.parse(uriString);

اگر از قبل از ارائه‌دهنده محتوا استفاده می‌کنید، ممکن است بخواهید مسیر URI جدیدی اضافه کنید که نشان می‌دهد URI برای کپی کردن است. برای مثال، فرض کنید ازقبل مسیرهای URI زیر را دارید:

"content://com.example.contacts/people"
"content://com.example.contacts/people/detail"
"content://com.example.contacts/people/images"

می‌توانید مسیر دیگری برای کپی کردن URI اضافه کنید:

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

سپس می‌توانید URI «کپی» را با تطبیق الگو شناسایی کنید و آن را با کدی که مختص کپی و جای‌گذاری است مدیریت کنید.

اگر از قبل از ارائه‌دهنده محتوا، پایگاه داده داخلی، یا جدول داخلی برای سازمان‌دهی داده‌هایتان استفاده می‌کنید، معمولاً از روش کدگذاری استفاده می‌کنید. در این موارد، چند داده دارید که می‌خواهید کپی کنید، و احتمالاً یک شناسه منحصربه‌فرد برای هرکدام وجود دارد. در پاسخ به پُرسمان از برنامه جای‌گذاری، می‌توانید داده‌ها را با شناسه آن جستجو کنید و آن را برگردانید.

اگر چندین داده ندارید، احتمالاً نیازی به کدگذاری شناسه ندارید. می‌توانید از «شناسه منبع یکسان» (URI) استفاده کنید که برای ارائه‌دهنده شما منحصربه‌فرد است. در پاسخ به پُرسمان، ارائه‌دهنده شما داده‌هایی را که درحال‌حاضر دارد برمی‌گرداند.

کپی کردن ساختارهای داده

یک ارائه‌دهنده محتوا برای کپی و جای‌گذاری داده‌های پیچیده به‌عنوان زیرکلاس مؤلفه ContentProvider راه‌اندازی کنید. شناسه منبع یکسان را که در بریده‌دان قرار داده‌اید کدبندی کنید تا به همان رکوردی اشاره کند که می‌خواهید ارائه دهید. علاوه‌براین، وضعیت فعلی برنامه‌تان را درنظر بگیرید:

  • اگر ازقبل ارائه‌دهنده محتوا دارید، می‌توانید به عملکرد آن اضافه کنید. ممکن است فقط لازم باشد روش query() آن را تغییر دهید تا شناسه‌های منبع یکسان را که از برنامه‌هایی می‌آیند که می‌خواهند داده‌ها را جای‌گذاری کنند مدیریت کند. احتمالاً می‌خواهید روش را برای مدیریت الگوی URI «کپی» اصلاح کنید.
  • اگر برنامه شما پایگاه داده داخلی را حفظ می‌کند، ممکن است بخواهید این پایگاه داده را به ارائه‌دهنده محتوا منتقل کنید تا کپی کردن از آن تسهیل شود.
  • اگر از پایگاه داده استفاده نمی‌کنید، می‌توانید ارائه‌دهنده محتوای ساده‌ای را پیاده‌سازی کنید که تنها هدف آن ارائه داده به برنامه‌هایی است که از بریده‌دان جای‌گذاری می‌کنند.

در ارائه‌دهنده محتوا، حداقل روش‌های زیر را لغو کنید:

query()
برنامه‌های جای‌گذاری فرض می‌کنند که می‌توانند داده‌های شما را بااستفاده از این روش با URI که در کلیپ‌بورد قرار داده‌اید دریافت کنند. برای پشتیبانی از کپی کردن، این روش باید URIهای حاوی مسیر ویژه «کپی» را شناسایی کند. سپس برنامه شما می‌تواند یک URI «کپی» ایجاد کند تا در بریده‌دان قرار دهد، که حاوی مسیر کپی و اشاره‌گری به رکورد دقیقی است که می‌خواهید کپی کنید.
getType()
این روش باید انواع MIME را برای داده‌هایی که قصد کپی کردنشان را دارید برگرداند. روش newUri() getType() را فراخوانی می‌کند تا انواع MIME را در شیء جدید ClipData قرار دهد.

انواع 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. در فعالیتی که کاربران داده‌ها را از آن کپی می‌کنند، کد را برای کپی کردن داده‌ها در بریده‌دان تنظیم کنید. در پاسخ به درخواست کپی، شناسه منبع یکسان را در بریده‌دان قرار دهید.

    کاتلین

    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. روش getType() را برای برگرداندن نوع MIME مناسب برای داده‌های کپی‌شده راه‌اندازی کنید:

    کاتلین

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

بخش جای‌گذاری داده‌ها از شناسه منبع یکسان محتوا نحوه دریافت شناسه منبع یکسان محتوا از بریده‌دان و استفاده از آن برای دریافت و جای‌گذاری داده‌ها را شرح می‌دهد.

کپی کردن جریان‌های داده‌ها

می‌توانید حجم زیادی از نوشتار و داده‌های دودویی را به‌صورت جاری‌سازی کپی و جای‌گذاری کنید. داده‌ها می‌توانند به شکل‌های زیر باشند:

  • فایل‌های ذخیره‌شده در دستگاه واقعی
  • جریان‌ها از سوکت‌ها
  • مقادیر زیادی داده ذخیره‌شده در سیستم پایگاه داده زیربنایی ارائه‌دهنده

ارائه‌دهنده محتوا برای جاری‌سازی‌های داده، دسترسی به داده‌هایش را با شیء توصیف‌گر فایل، مثل AssetFileDescriptor، به‌جای شیء Cursor فراهم می‌کند. برنامه جای‌گذاری‌کننده بااستفاده از این توصیف‌گر فایل، جریان داده را می‌خواند.

برای راه‌اندازی برنامه‌تان جهت کپی کردن جاری‌سازی داده با ارائه‌دهنده، این مراحل را دنبال کنید:

  1. برای جاری‌سازی داده‌ای که در بریده‌دان قرار می‌دهید، شناسه منبع یکسان محتوا راه‌اندازی کنید. گزینه‌های انجام این کار شامل موارد زیر است:
    • همان‌طور که در بخش کدبندی شناسه در URI شرح داده شده است، شناسه‌ای را برای جاری‌سازی داده در URI کدبندی کنید و سپس جدولی را در ارائه‌دهنده خود نگه دارید که حاوی شناسه‌ها و نام جاری‌سازی مربوطه باشد.
    • نام جاری‌سازی را مستقیماً در URI کدگذاری کنید.
    • از URI یکتایی استفاده کنید که همیشه جاری‌سازی فعلی را از ارائه‌دهنده برمی‌گرداند. اگر از این گزینه استفاده می‌کنید، فراموش نکنید که ارائه‌دهنده خود را به‌روز کنید تا هرگاه جاری‌سازی را بااستفاده از URI در بریده‌دان کپی می‌کنید، به جاری‌سازی دیگری اشاره کند.
  2. برای هر نوع جاری‌سازی داده‌ای که قصد دارید ارائه دهید، یک نوع MIME ارائه دهید. برنامه‌های جای‌گذاری به این اطلاعات نیاز دارند تا تعیین کنند که آیا می‌توانند داده‌ها را در بریده‌دان جای‌گذاری کنند یا نه.
  3. یکی از روش‌های ContentProvider را که توصیف‌گر فایل را برای جریانی برمی‌گرداند پیاده‌سازی کنید. اگر شناسه‌ها را در شناسه منبع یکسان محتوا کدگذاری می‌کنید، از این روش برای تعیین اینکه کدام جاری‌سازی باز شود استفاده کنید.
  4. برای کپی کردن جریان داده در بریده‌دان، شناسه منبع یکسان محتوا را بسازید و آن را در بریده‌دان قرار دهید.

برای جای‌گذاری کردن جاری‌سازی داده، برنامه کلیپ را از بریده‌دان دریافت می‌کند، URI را دریافت می‌کند، و از آن در فراخوانی روش توصیف‌گر فایل ContentResolver که جاری‌سازی را باز می‌کند استفاده می‌کند. روش ContentResolver روش ContentProvider مربوطه را فراخوانی می‌کند، و شناسه منبع یکسان محتوا را به آن ارسال می‌کند. ارائه‌دهنده شما توصیف‌گر فایل را به روش ContentResolver برمی‌گرداند. سپس برنامه جای‌گذاری مسئولیت دارد داده‌ها را از جاری‌سازی بخواند.

The following list shows the most important file descriptor methods for a content provider. هرکدام از این‌ها یک روش ContentResolver متناظر دارد که رشته «Descriptor» به نام روش پیوست شده است. برای مثال، ContentResolver آنالوگ openAssetFile() openAssetFileDescriptor() است.

openTypedAssetFile()

این روش توصیف‌گر فایل دارایی را برمی‌گرداند، اما فقط درصورتی‌که نوع MIME ارائه‌شده توسط ارائه‌دهنده پشتیبانی شود. فراخواننده (برنامه‌ای که جای‌گذاری را انجام می‌دهد) الگوی نوع رسانه را ارائه می‌دهد. ارائه‌دهنده محتوای برنامه‌ای که URI را در کلیپ‌بورد کپی می‌کند، اگر بتواند آن نوع MIME را ارائه دهد، یک اداره‌کننده فایل AssetFileDescriptor برمی‌گرداند و اگر نتواند، استثنایی ایجاد می‌کند.

این روش زیربخش‌های فایل‌ها را مدیریت می‌کند. می‌توانید از آن برای خواندن دارایی‌هایی که ارائه‌دهنده محتوا در بریده‌دان کپی کرده است استفاده کنید.

openAssetFile()
این روش شکل کلی‌تری از openTypedAssetFile() است. این مدل برای انواع MIME مجاز فیلتر نمی‌کند، اما می‌تواند زیربخش‌های فایل‌ها را بخواند.
openFile()
این شکل کلی‌تری از openAssetFile() است. نمی‌تواند زیربخش‌های فایل‌ها را بخواند.

درصورت تمایل می‌توانید از روش openPipeHelper() با روش توصیف‌گر فایل استفاده کنید. این کار به برنامه جای‌گذاری اجازه می‌دهد داده‌های جاری را در رشته پس‌زمینه بااستفاده از لوله بخواند. برای استفاده از این روش، میانای ContentProvider.PipeDataWriter را پیاده‌سازی کنید.

طراحی عملکرد کپی و جای‌گذاری مؤثر

برای طراحی عملکرد مؤثر کپی و جای‌گذاری برای برنامه‌تان، این نکات را به‌خاطر بسپارید:

  • در هر زمان، فقط یک کلیپ در بریده‌دان وجود دارد. عملیات کپی جدید توسط هر برنامه‌ای در سیستم، کلیپ قبلی را رونویسی می‌کند. ازآنجایی‌که ممکن است کاربر از برنامه شما خارج شود و قبل‌از بازگشت، محتوایی را کپی کند، نمی‌توانید فرض کنید که کلیپ‌بورد حاوی کلیپی است که کاربر قبلاً در برنامه شما کپی کرده است.
  • هدف از وجود چند شیء ClipData.Item در هر کلیپ، پشتیبانی از کپی و جای‌گذاری چند انتخاب است، نه اشکال مختلف ارجاع به یک انتخاب. معمولاً می‌خواهید همه اشیای ClipData.Item در کلیپ شکل یکسانی داشته باشند. یعنی همه آن‌ها باید نوشتار ساده، شناسه منبع یکسان محتوا، یا Intent باشند و نباید ترکیبی باشند.
  • وقتی داده ارائه می‌کنید، می‌توانید نمایش‌های MIME مختلفی ارائه دهید. انواع MIME را که پشتیبانی می‌کنید به ClipDescription اضافه کنید، سپس انواع MIME را در ارائه‌دهنده محتوایتان پیاده‌سازی کنید.
  • وقتی داده‌ها را از بریده‌دان دریافت می‌کنید، برنامه شما مسئول بررسی انواع MIME دردسترس و سپس تصمیم‌گیری درباره این است که از کدام‌یک (درصورت وجود) استفاده کند. حتی اگر کلیپی در بریده‌دان وجود داشته باشد و کاربر درخواست جای‌گذاری کند، برنامه شما ملزم به انجام جای‌گذاری نیست. اگر نوع MIME سازگار است، جای‌گذاری را انجام دهید. می‌توانید بااستفاده از coerceToText()، داده‌های موجود در بریده‌دان را به نوشتار تبدیل کنید. اگر برنامه شما از بیش‌از یکی از انواع MIME موجود پشتیبانی می‌کند، می‌توانید به کاربر اجازه دهید انتخاب کند از کدام‌یک استفاده شود.