يوفّر Android إطار عمل قويًا يستند إلى الحافظة لعمليات النسخ واللصق. وهو يتيح أنواع بيانات بسيطة ومعقدة، بما في ذلك سلاسل النصوص وبنى البيانات المعقدة وبيانات تدفق النصوص والثنائيات وأصول التطبيقات. يتم تخزين بيانات النصوص البسيطة مباشرةً في الحافظة، في حين يتم تخزين البيانات المعقدة كمرجع يحلّه تطبيق اللصق مع مقدّم المحتوى. تعمل ميزة النسخ واللصق داخل التطبيق وبين التطبيقات التي تنفِّذ الإطار العملي.
بما أنّ جزءًا من إطار العمل يستخدم مقدّمي المحتوى، يفترض هذا المستند بعض الإلمام بواجهة برمجة التطبيقات Android Content Provider API الموضّحة في مقدّمو المحتوى.
يتوقع المستخدمون تلقّي ملاحظات عند نسخ المحتوى إلى الحافظة، لذا بالإضافة إلى إطار العمل الذي يُمكّن من النسخ واللصق، يعرض Android واجهة مستخدم تلقائية للمستخدمين عند النسخ في الإصدار 13 من نظام التشغيل Android (المستوى 33 لواجهة برمجة التطبيقات) والإصدارات الأحدث. بسبب هذه الميزة، هناك خطر ظهور إشعارات مكرّرة. يمكنك الاطّلاع على مزيد من المعلومات حول هذه الحالة الخاصة في القسم تجنُّب الإشعارات المكرّرة.
تقديم ملاحظات للمستخدمين يدويًا عند نسخ المحتوى في الإصدار Android 12L (المستوى 32 لواجهة برمجة التطبيقات) والإصدارات الأقدم اطّلِع على الاقتراحات المتعلّقة بهذا في هذا المستند.
إطار عمل الحافظة
عند استخدام إطار عمل الحافظة، ضَع البيانات في عنصر مقطع، ثم ضَع عنصر المقطع في الحافظة على مستوى النظام. يمكن أن يتّخذ عنصر المقطع أحد الأشكال الثلاثة التالية:
- نص
- سلسلة نصية. ضع السلسلة مباشرةً في عنصر المقطع، ثم ضعه في حافظة النصوص. للصق السلسلة، احصل على عنصر المقطع من الحافظة وانسخ السلسلة إلى مساحة تخزين تطبيقك.
- URI
-
عنصر
Uri
يمثّل أي شكل من أشكال معرّف الموارد المنتظم (URI). يُستخدَم هذا الإجراء بشكل أساسي لنسخ البيانات المعقدة من موفّر المحتوى. لنسخ بيانات، ضَع عنصرUri
في عنصر مقطع وضع عنصر المقطع في حافظة النصوص. ولصق البيانات، احصل على عنصر المقطع، واحصل على عنصرUri
، وحوِّله إلى مصدر بيانات، مثل مزوّد محتوى، وانسخ البيانات من المصدر إلى مساحة تخزين تطبيقك. - النيّة
-
Intent
. يتيح هذا الإجراء نسخ اختصارات التطبيقات. لنسخ البيانات، أنشئ رمزIntent
، ثم ضعه في عنصر مقطع، ثم ضع عنصر المقطع في الحافظة. ولصق البيانات، احصل على عنصر المقطع، ثم انسخ عنصرIntent
إلى منطقة ذاكرة تطبيقك.
لا تحتوي الحافظة على عنصر مقطع واحد فقط في المرة الواحدة. عندما يضع أحد التطبيقات عنصر مقطع في ملف النسخ المُعدّ، يختفي عنصر المقطع السابق.
إذا كنت تريد السماح للمستخدمين بلصق البيانات في تطبيقك، ليس عليك معالجة جميع أنواع البيانات. يمكنك فحص البيانات في الحافظة قبل منح المستخدمين خيار لصقها. بالإضافة إلى تنسيق بيانات معيّن، يحتوي عنصر المقطع أيضًا على بيانات وصفية تُعلمك بأنواع ملف MIME المتوفّرة. تساعدك بيانات التعريف هذه في تحديد ما إذا كان بإمكان تطبيقك تنفيذ إجراء مفيد باستخدام بيانات الحافظة. على سبيل المثال، إذا كان لديك تطبيق يعالج النصوص في المقام الأول، قد تريد تجاهل عناصر المقاطع التي تحتوي على معرّف موارد منتظم أو نية.
يمكنك أيضًا السماح للمستخدمين بلصق النص بغض النظر عن شكل البيانات في الحافظة. للقيام بذلك، اجبر بيانات الحافظة على تمثيل نصي، ثم الصق هذا النص. تم توضيح ذلك في القسم تحويل الحافظة إلى نص.
فئات الحافظة
يصف هذا القسم الفئات التي يستخدمها إطار عمل الحافظة.
ClipboardManager
يتم تمثيل حافظة نظام Android من خلال فئة
ClipboardManager
الشاملة.
لا تنشئ مثيلًا لهذه الفئة مباشرةً. بدلاً من ذلك، يمكنك الحصول على إشارة إليه من خلال استدعاء
getSystemService(CLIPBOARD_SERVICE)
.
ClipData وClipData.Item وClipDescription
لإضافة بيانات إلى الحافظة، أنشئ عنصر
ClipData
يحتوي على
وصف للبيانات والبيانات نفسها. يمكن للحافظة الاحتفاظ بClipData
واحد فقط في كل
وقت. يحتوي ClipData
على كائن
ClipDescription
وكائن واحد أو أكثر
ClipData.Item
.
يحتوي عنصر ClipDescription
على بيانات وصفية عن المقطع. على وجه الخصوص، يحتوي على صفيف من أنواع MIME المتاحة لبيانات المقطع. بالإضافة إلى ذلك، في الإصدار 12 من نظام التشغيل Android (المستوى 31 لواجهة برمجة التطبيقات) والإصدارات الأحدث، تتضمّن البيانات الوصفية معلومات حول ما إذا كان الكائن يحتوي على نص منمق ونوع النص في الكائن.
عند وضع مقطع في الحافظة، تتوفّر هذه المعلومات لتطبيقات اللصق التي
يمكنها فحص ما إذا كان بإمكانها معالجة بيانات المقطع.
يحتوي عنصر ClipData.Item
على النص أو معرّف الموارد المنتظم (URI) أو بيانات النية:
- نص
-
أ
CharSequence
. - 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
. إذا كان عنوان URL هو عنوان URL للمحتوى، أي إذا كانUri.getScheme()
يعرضcontent:
، تستخدِم الطريقة العنصرContentResolver
المقدَّم فيresolver
لاسترداد أنواع MIME المتاحة من مقدّم المحتوى. وبعد ذلك، يتم تخزينها فيClipDescription
. بالنسبة إلى معرّف الموارد المنتظم (URI) الذي ليس معرّف مواردcontent:
، تضبط الطريقة نوع MIME علىMIMETYPE_TEXT_URILIST
.استخدِم
newUri()
لإنشاء مقطع من عنوان URL، خاصةً عنوانcontent:
URL. -
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
هو معرّف موارد منتظم، أي إذا كانgetUri()
غير صفري، يحاولcoerceToText()
استخدامه كمعرّف موارد منتظم للمحتوى.- إذا كان معرّف الموارد المنتظم هو معرّف موارد منتظم للمحتوى وكان بإمكان الموفّر عرض بث نصي،
تعرِض
coerceToText()
بثًا نصيًا. - إذا كان معرّف الموارد المنتظم هو معرّف موارد منتظم للمحتوى ولكنّ مقدّم الخدمة لا يقدّم بثًا نصيًا،
تعرِض
coerceToText()
تمثيلًا لمعرّف الموارد المنتظم. يكون التمثيل هو نفسه التمثيل الذي يعرضهUri.toString()
. - إذا لم يكن عنوان URL هو عنوان URL للمحتوى، تعرض
coerceToText()
تمثيلاً ل عنوان URL. التمثيل هو نفسه التمثيل الذي يعرضهUri.toString()
.
- إذا كان معرّف الموارد المنتظم هو معرّف موارد منتظم للمحتوى وكان بإمكان الموفّر عرض بث نصي،
تعرِض
- النيّة
- إذا كان
ClipData.Item
Intent
، أي إذا كانgetIntent()
غير صفري، تحوّله الدالةcoerceToText()
إلى معرّف موارد منتظم للنشاط وتُعرِضه. التمثيل هو نفسه التمثيل الذي يعرضهIntent.toUri(URI_INTENT_SCHEME)
.
تم تلخيص إطار عمل الحافظة في الشكل 2. لنسخ البيانات، يضع التطبيق عنصر
ClipData
في الحافظة الشاملة ClipboardManager
. يحتوي العنصر
ClipData
على عنصر ClipData.Item
واحد أو أكثر وعنصر
ClipDescription
واحد. ولصق البيانات، يحصل التطبيق على ClipData
، ويحصل على نوع MIME من ClipDescription
، ويحصل على البيانات من
ClipData.Item
أو من موفّر المحتوى المُشار إليه في
ClipData.Item
.
النسخ إلى الحافظة
لنسخ البيانات إلى الحافظة، احصل على معرّف للعنصر ClipboardManager
العام،
وأنشئ عنصر ClipData
، وأضِف عنصر ClipDescription
وعنصرًا واحدًا أو أكثر
ClipData.Item
إليه. بعد ذلك، أضِف عنصر ClipData
المكتمل إلى ClipboardManager
. يتم وصف ذلك بالتفصيل في الإجراء التالي:
- إذا كنت تنسخ البيانات باستخدام معرّف موارد منتظم للمحتوى، عليك إعداد مقدّم محتوى.
- الحصول على الحافظة في النظام:
Kotlin
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 } }
Java
... // If the user selects copy. case R.id.menu_copy: // Gets a handle to the clipboard service. ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
-
انسخ البيانات إلى عنصر
ClipData
جديد:-
بالنسبة إلى النص
Kotlin
// Creates a new text clip to put on the clipboard. val clip: ClipData = ClipData.newPlainText("simple text", "Hello, World!")
Java
// Creates a new text clip to put on the clipboard. ClipData clip = ClipData.newPlainText("simple text", "Hello, World!");
-
بالنسبة إلى عنوان URI
ينشئ هذا المقتطف معرّف موارد منتظم (URI) من خلال ترميز معرّف السجلّ في معرّف الموارد المنتظم للمحتوى الخاص بالموفّر. يمكنك الاطّلاع على مزيد من التفاصيل حول هذه الطريقة في القسم ترميز معرّف في معرّف الموارد المنتظم (URI).
Kotlin
// 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)
Java
// 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
لتطبيق معيّن، ثم يضع ذلك في عنصر المقطع:Kotlin
// 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)
Java
// 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);
-
بالنسبة إلى النص
-
ضع عنصر المقطع الجديد في الحافظة:
Kotlin
// Set the clipboard's primary clip. clipboard.setPrimaryClip(clip)
Java
// Set the clipboard's primary clip. clipboard.setPrimaryClip(clip);
تقديم ملاحظات عند النسخ إلى الحافظة
يتوقع المستخدمون الحصول على ملاحظات مرئية عندما ينسخ تطبيق محتوى إلى الحافظة. يتم تنفيذ ذلك تلقائيًا للمستخدمين الذين يستخدمون الإصدار 13 من نظام التشغيل Android والإصدارات الأحدث، ولكن يجب تنفيذه يدويًا في الإصدارات السابقة.
بدءًا من Android 13، يعرض النظام تأكيدًا مرئيًا عاديًا عند إضافة محتوى إلى الحافظة. ينفّذ التأكيد الجديد ما يلي:
- تأكيد على أنّه تم نسخ المحتوى بنجاح
- يوفّر معاينة للمحتوى المنسوخ.
في الإصدار 12L من نظام التشغيل Android (المستوى 32 لواجهة برمجة التطبيقات) والإصدارات الأقدم، قد لا يكون المستخدمون متأكدين مما إذا كانوا قد نسخوا المحتوى بنجاح أو ما نسخوه. تعمل هذه الميزة على توحيد الإشعارات المختلفة التي تعرضها التطبيقات بعد النسخ، وتمنح المستخدمين مزيدًا من التحكّم في الحافظة.
تجنُّب الإشعارات المكرّرة
في الإصدار 12L من نظام Android (المستوى 32 لواجهة برمجة التطبيقات) والإصدارات الأقدم، ننصحك بتنبيه المستخدمين عند نسخ المحتوى بنجاح
من خلال تقديم ملاحظات مرئية داخل التطبيق باستخدام تطبيق مصغّر مثل Toast
أو
Snackbar
بعد النسخ.
لتجنُّب عرض المعلومات بشكلٍ مكرّر، ننصحك بشدة بإزالة الإشعارات القصيرة أو أشرطة المعلومات الصغيرة التي تظهر بعد نسخة داخل التطبيق لنظام التشغيل 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() }
إضافة محتوى حسّاس إلى الحافظة
إذا كان تطبيقك يتيح للمستخدمين نسخ محتوى حسّاس إلى الحافظة، مثل كلمات المرور أو معلومات بطاقة الائتمان، يجب إضافة علامة إلى ClipDescription
في ClipData
قبل استدعاء ClipboardManager.setPrimaryClip()
. تؤدي إضافة هذه العلامة إلى منع ظهور المحتوى
الحسّاس في التأكيد المرئي للمحتوى المنسوخ في الإصدار 13 من نظام التشغيل 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) } }
اللصق من الحافظة
كما هو موضّح سابقًا، يمكنك لصق البيانات من الحافظة من خلال الحصول على عنصر الحافظة العام، والحصول على عنصر المقطع، والاطّلاع على بياناته، ونسخ البيانات من عنصر المقطع إلى مساحة التخزين الخاصة بك إن أمكن. يوضّح هذا القسم بالتفصيل كيفية لصق الأشكال الثلاثة لبيانات clipboard.
لصق نص عادي
للصق نص عادي، احصل على الحافظة الشاملة وتأكَّد من أنّه يمكنها عرض نص عادي. بعد ذلك، احصل على
عنصر المقطع وانسخ نصه إلى مساحة التخزين الخاصة بك باستخدام getText()
، كما هو موضّح في
الإجراء التالي:
- احصل على الكائن الشامل
ClipboardManager
باستخدامgetSystemService(CLIPBOARD_SERVICE)
. يمكنك أيضًا تحديد متغيّر عام يحتوي على النص الذي تمّ لصقه:Kotlin
var clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager var pasteData: String = ""
Java
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); String pasteData = "";
- حدِّد ما إذا كنت بحاجة إلى تفعيل خيار "لصق" أو إيقافه في
النشاط الحالي. تأكَّد من أنّ الحافظة تحتوي على مقطع وأنّه يمكنك التعامل مع نوع البيانات
التي يمثّلها المقطع:
Kotlin
// 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 } }
Java
// 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); }
- انسخ البيانات من الحافظة. لا يمكن الوصول إلى هذه النقطة في الرمز إلا إذا كان
خيار القائمة "لصق" مفعّلاً، لذا يمكنك افتراض أنّ الحافظة تحتوي على
نص عادي. لا تعرف بعد ما إذا كان يحتوي على سلسلة نصية أو معرّف موارد منتظم يشير إلى نص عادي.
يختبر مقتطف الرمز التالي ذلك، ولكنه يعرض فقط الرمز المخصّص لمعالجة النص العادي:
Kotlin
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 } } } }
Java
// 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
واطلب من طريقة مقدّم المحتوى المناسبة استرداد البيانات.
يوضّح الإجراء التالي كيفية الحصول على البيانات من موفّر محتوى استنادًا إلى رابط محتوى موحّد (URI) في الحافظة. يتحقّق من توفّر نوع MIME يمكن للتطبيق استخدامه من العميل.
-
يمكنك تحديد متغيّر عام يحتوي على نوع MIME:
Kotlin
// 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"
Java
// 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";
- الحصول على الحافظة الشاملة احصل أيضًا على أداة حلّ لمشاكل المحتوى حتى تتمكّن من الوصول إلى مقدّم
المحتوى:
Kotlin
// Gets a handle to the Clipboard Manager. val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager // Gets a content resolver instance. val cr = contentResolver
Java
// Gets a handle to the Clipboard Manager. ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); // Gets a content resolver instance. ContentResolver cr = getContentResolver();
- احصل على المقطع الأساسي من الحافظة واحصل على محتوياته كعنوان URL:
Kotlin
// 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
Java
// 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();
- يمكنك اختبار ما إذا كان معرّف الموارد المنتظم هو معرّف موارد منتظم للمحتوى من خلال الاتصال بـ
getType(Uri)
. تعرِض هذه الطريقة قيمة فارغة إذا لم تشيرUri
إلى مقدّم محتوى صالح.Kotlin
// If the clipboard contains a URI reference... pasteUri?.let { // ...is this a content URI? val uriMimeType: String? = cr.getType(it)
Java
// If the clipboard contains a URI reference... if (pasteUri != null) { // ...is this a content URI? String uriMimeType = cr.getType(pasteUri);
- اختبِر ما إذا كان مقدّم المحتوى يتيح استخدام نوع MIME يتوافق مع التطبيق. إذا
كان الأمر كذلك، يُرجى الاتصال بالرقم
ContentResolver.query()
للحصول على البيانات. قيمة الإرجاع هيCursor
.Kotlin
// 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. } } } }
Java
// 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()
لنسخ
intent إلى مساحة التخزين الخاصة بك. يوضّح المقتطف التالي ذلك:
Kotlin
// 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. }
Java
// 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 (مستوى واجهة برمجة التطبيقات 31) والإصدارات الأحدث، يعرض النظام عادةً رسالة فورية عندما يُطلِب تطبيقك
getPrimaryClip()
.
يتضمّن النص داخل الرسالة التنسيق التالي:
APP pasted from your clipboard
لا يعرض النظام رسالة فورية عندما ينفّذ تطبيقك أحد الإجراءات التالية:
- الوصول إلى
ClipData
من تطبيقك - الوصول بشكل متكرّر إلى
ClipData
من تطبيق معيّن. لا يظهر إشعار الشاشة المنبثقة إلا عند وصول تطبيقك إلى البيانات من هذا التطبيق للمرة الأولى. - يسترجع البيانات الوصفية لكائن المقطع، مثلاً من خلال استدعاء
getPrimaryClipDescription()
بدلاً منgetPrimaryClip()
.
استخدام موفّري المحتوى لنسخ البيانات المعقدة
يسمح مقدّمو المحتوى بنسخ البيانات المعقدة، مثل سجلّات قاعدة البيانات أو مصادر ملفات. لنسخ البيانات، ضَع معرّف موارد منتظم للمحتوى في الحافظة. تحصل تطبيقات اللصق بعد ذلك على معرّف الموارد المنتظم هذا من ملف الحافظة وتستخدمه لاسترداد بيانات قاعدة البيانات أو أوصاف تدفق الملفات.
بما أنّ تطبيق اللصق لا يحتوي إلا على معرّف الموارد المنتظم للمحتوى الخاص ببياناتك، يجب أن يعرف قطعة البيانات التي يجب استرجاعها. يمكنك تقديم هذه المعلومات من خلال ترميز معرّف للبيانات في معرّف الموارد المنتظم نفسه، أو يمكنك تقديم معرّف موارد منتظم فريد يعرض البيانات التي تريد نسخها. يعتمد أسلوب التحليل الذي تختاره على طريقة تنظيم بياناتك.
توضّح الأقسام التالية كيفية إعداد معرّفات URI وتقديم بيانات معقّدة وتقديم ملف البث. تفترض الأوصاف أنّك على دراية بالمبادئ العامة لتصميم موفّري المحتوى.
ترميز معرّف في معرّف الموارد المنتظم (URI)
من الأساليب المفيدة لنسخ البيانات إلى الحافظة باستخدام معرّف الموارد المنتظم (URI) هي ترميز معرّف ل data في معرّف الموارد المنتظم نفسه. يمكن لموفّر المحتوى بعد ذلك الحصول على المعرّف من عنوان URL واستخدامه لاسترداد البيانات. ولا يلزم أن يعرف تطبيق اللصق بوجود المعرّف. ما عليه سوى الحصول على "المرجع"، أي معرّف الموارد المنتظم بالإضافة إلى المعرّف، من ممّرة النسخ واللصق، وإرساله إلى مقدّم المحتوى، واسترداد البيانات.
يتم عادةً ترميز معرّف في معرّف موارد منتظم للمحتوى من خلال إلحاقه بنهاية معرّف الموارد المنتظم. على سبيل المثال، لنفترض أنّك حدّدت معرّف الموارد المنتظم لمقدّم الخدمة على النحو التالي:
"content://com.example.contacts"
إذا كنت تريد ترميز اسم في معرّف الموارد المنتظم هذا، استخدِم مقتطف الرمز التالي:
Kotlin
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)
Java
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);
إذا كنت تستخدم حاليًا مقدّم محتوى، ننصحك بإضافة مسار معرّف موارد منتظم جديد يشير إلى أنّ معرّف الموارد المنتظم مخصّص للنسخ. على سبيل المثال، لنفترض أنّ لديك مسارات عناوين URL التالية:
"content://com.example.contacts/people" "content://com.example.contacts/people/detail" "content://com.example.contacts/people/images"
يمكنك إضافة مسار آخر لنسخ عناوين URL:
"content://com.example.contacts/copying"
يمكنك بعد ذلك رصد عنوان URL "للنسخ" من خلال مطابقة الأنماط ومعالجته باستخدام رمز مخصّص للنسخ واللصق.
يتم استخدام أسلوب الترميز عادةً إذا كنت تستخدم حاليًا مزوّد محتوى أو قاعدة بيانات داخلية أو جدولًا داخليًا لتنظيم بياناتك. في هذه الحالات، يكون لديك عدة أجزاء من البيانات التي تريد نسخها، ومن المفترض أن يكون لكل جزء معرّف فريد. استجابةً لاستعلام من تطبيق لصق البيانات، يمكنك البحث عن البيانات حسب معرّفها وإعادتها.
إذا لم يكن لديك عدة أجزاء من البيانات، من المحتمل ألا تحتاج إلى ترميز معرّف. يمكنك استخدام معرّف موارد فريد لموفّر الخدمة. ردًا على طلب بحث، يعرض مقدّم الخدمة البيانات التي يتضمّنها حاليًا.
نسخ هياكل البيانات
إعداد موفِّر محتوى لنسخ البيانات المعقدة ولصقها كصنف فرعي من العنصر
ContentProvider
أدخِل ترميزًا لعنوان URL الذي تضعه في الحافظة كي يشير إلى السجلّ الدقيق الذي تريد
تقديمه. بالإضافة إلى ذلك، ننصحك بالاطّلاع على الحالة الحالية لتطبيقك:
- إذا كان لديك مقدّم محتوى، يمكنك إضافة وظائف إليه. قد تحتاج فقط
إلى تعديل طريقة
query()
لمعالجة عناوين URL الواردة من التطبيقات التي تريد لصق البيانات. من المحتمل أن تريد تعديل الطريقة للتعامل مع نمط عنوان URL "copy". - إذا كان تطبيقك يحتفظ بقاعدة بيانات داخلية، قد تحتاج إلى نقل قاعدة البيانات هذه إلى مقدّم محتوى لتسهيل النسخ منها.
- إذا لم تكن تستخدم قاعدة بيانات، يمكنك تنفيذ موفِّر محتوى بسيط الغرض الوحيد منه هو تقديم البيانات إلى التطبيقات التي تنسخها من الحافظة.
في موفّر المحتوى، يمكنك إلغاء الطرق التالية على الأقل:
-
query()
- تفترض تطبيقات اللصق أنّه يمكنها الحصول على بياناتك باستخدام هذه الطريقة مع عنوان URI الذي تضعه في الحافظة. لإتاحة النسخ، يجب أن ترصد هذه الطريقة عناوين URL التي تحتوي على مسار "copy" خاص. يمكن لتطبيقك بعد ذلك إنشاء عنوان URL لـ "النسخ" لوضعه في ملف الحافظة الذي يحتوي على مسار النسخ ومُشير إلى السجلّ الدقيق الذي تريد نسخه.
-
getType()
- يجب أن تعرِض هذه الطريقة أنواع MIME للبيانات التي تريد نسخها. تستدعي الطريقة
newUri()
getType()
لوضع أنواع MIME فيClipData
كائن جديد.يتم وصف أنواع MIME للبيانات المعقدة في موفّرو المحتوى.
لست بحاجة إلى استخدام أي من طرق مقدّمي المحتوى الأخرى، مثل
insert()
أو
update()
.
ما على تطبيق اللصق سوى الحصول على أنواع بروتوكول MIME المتوافقة ونسخ البيانات من مقدّم الخدمة.
إذا كانت هذه الطرق متوفّرة لديك، لن تتداخل مع عمليات النسخ.
توضِّح المقتطفات التالية كيفية إعداد تطبيقك لنسخ البيانات المعقدة:
-
في الثوابت العالمية لتطبيقك، أدخِل سلسلة عنوان URI أساسيًا ومسارًا يحددان سلاسل عناوين URI التي تستخدِمها لنسخ البيانات. يجب أيضًا تحديد نوع MIME للبيانات المُنسخة.
Kotlin
// 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"
Java
// Declares the base URI string. private static final String CONTACTS = "content://com.example.contacts"; // Declares a path string for URIs that you use to copy data. private static final String COPY_PATH = "/copy"; // Declares a MIME type for the copied data. public static final String MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact";
- في النشاط الذي ينسخ المستخدمون البيانات منه، يمكنك إعداد الرمز البرمجي لنسخ البيانات إلى الحافظة.
استجابةً لطلب نسخ، ضَع معرّف الموارد المنتظم (URI) في الحافظة.
Kotlin
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) } }
Java
public class MyCopyActivity extends Activity { ... // The user has selected a name and is requesting a copy. case R.id.menu_copy: // Appends the last name to the base URI. // The name is stored in "lastName". uriString = CONTACTS + COPY_PATH + "/" + lastName; // Parses the string into a URI. Uri copyUri = Uri.parse(uriString); // Gets a handle to the clipboard service. ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newUri(getContentResolver(), "URI", copyUri); // Sets the clipboard's primary clip. clipboard.setPrimaryClip(clip);
-
في النطاق العام لموفّر المحتوى، أنشئ أداة مطابقة لمعرّفات الموارد المنتظمة (URI) وأضِف نمطًا لمعرّف الموارد المنتظم (URI) يتطابق مع معرّفات الموارد المنتظمة (URI) التي تضعها في الحافظة.
Kotlin
// 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() { ... }
Java
public class MyCopyProvider extends ContentProvider { ... // A Uri Match object that simplifies matching content URIs to patterns. private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); // An integer to use in switching based on the incoming URI pattern. private static final int GET_SINGLE_CONTACT = 0; ... // Adds a matcher for the content URI. It matches // "content://com.example.contacts/copy/*" sUriMatcher.addURI(CONTACTS, "names/*", GET_SINGLE_CONTACT);
-
اضبط
query()
. يمكن لهذه الطريقة التعامل مع أنماط عناوين URL مختلفة، استنادًا إلى كيفية ترميزها، ولكن لا يظهر سوى نمط عملية النسخ إلى الحافظة.Kotlin
// 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. } } ... }
Java
// 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. ... }
-
يمكنك إعداد طريقة
getType()
لعرض نوع MIME مناسب للبيانات التي تم نسخها:Kotlin
// Sets up your provider's getType() method. override fun getType(uri: Uri): String? { ... return when(sUriMatcher.match(uri)) { GET_SINGLE_CONTACT -> MIME_TYPE_CONTACT ... } }
Java
// 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) للمحتوى من الحافظة واستخدامه للحصول على البيانات ولصقها.
نسخ مصادر البيانات
يمكنك نسخ ولصق كميات كبيرة من النصوص والبيانات الثنائية كبثّ. يمكن أن تتضمّن البيانات أشكالًا مثل ما يلي:
- الملفات المخزَّنة على الجهاز الفعلي
- مصادر البيانات من المقابس
- كميات كبيرة من البيانات المخزّنة في نظام قاعدة البيانات الأساسي لدى مقدّم الخدمة
يقدّم مقدّم المحتوى لملفات بيانات البث إمكانية الوصول إلى بياناته باستخدام كائن وصف الملف،
مثل
AssetFileDescriptor
،
بدلاً من كائن Cursor
. يقرأ تطبيق اللصق مصدر البيانات باستخدام ملف الوصف
هذا.
لإعداد تطبيقك لنسخ مصدر بيانات مع مزوّد، اتّبِع الخطوات التالية:
-
إعداد رابط محتوى موحّد لمصدر البيانات الذي تضعه في الحافظة تشمل الخيارات
التي يمكنك اتّخاذها لإجراء ذلك ما يلي:
- رمزِّ معرّفًا لمصدر البيانات في معرّف الموارد المنتظم (URI)، كما هو موضّح في القسم ترميز معرّف في معرّف الموارد المنتظم (URI)، ثم احتفظ بجدول في موفِّر البيانات يحتوي على المعرّفات واسم مصدر البيانات المقابل.
- رمزَي اسم البث مباشرةً في معرّف الموارد المنتظم (URI).
- استخدِم معرّف موارد منتظمًا فريدًا يعرض دائمًا البث الحالي من مقدّم الخدمة. في حال استخدام هذا الخيار، تذكَّر تعديل مقدّم الخدمة لتوجيهه إلى مصدر بيانات مختلف عند نسخ مصدر البيانات إلى الحافظة باستخدام معرّف الموارد المنتظم.
- أدخِل نوع MIME لكل نوع من مصادر البيانات التي تخطّط لتقديمها. تحتاج تطبيقات اللصق إلى هذه المعلومات لتحديد ما إذا كان بإمكانها لصق البيانات في الحافظة.
- نفِّذ إحدى طرق
ContentProvider
التي تُرجع واصف ملف لشدَّة البث. في حال ترميز المعرّفات في معرّف الموارد المنتظم للمحتوى، استخدِم هذه الطريقة لتحديد البث الذي تريد فتحه. - لنسخ مصدر البيانات إلى الحافظة، عليك إنشاء معرّف الموارد المنتظم للمحتوى ووضعه في الحافظة.
ولصق مصدر بيانات، يحصل التطبيق على المقطع من الحافظة، ويحصل على معرّف الموارد المنتظم، ويستخدمه
في طلب إلى طريقة وصف ملف ContentResolver
التي تفتح مصدر البيانات. تستدعي الطريقة
ContentResolver
الطريقة ContentProvider
المقابلة،
وتمرّر إليها معرّف الموارد المنتظم للمحتوى. يعرض موفِّر الخدمة وصف الملف إلى الأسلوب
ContentResolver
. بعد ذلك، يتحمّل تطبيق اللصق مسؤولية قراءة
البيانات من مصدر البيانات.
تعرض القائمة التالية أهم طرق وصف الملفات لموفّر المحتوى. ولكلٍّ
من هذه الطرق طريقة ContentResolver
مقابلة مع إلحاق السلسلة
"Descriptor" باسم الطريقة. على سبيل المثال، ContentResolver
المكافئ لopenAssetFile()
هو
openAssetFileDescriptor()
.
-
openTypedAssetFile()
-
تعرض هذه الطريقة وصفًا لملف مادة العرض، ولكن فقط إذا كان نوع MIME المقدَّم متوافقًا مع الموفِّر. يقدّم المُرسِل، أي التطبيق الذي يُجري عملية اللصق، نمطًا لنوع MIME. يعرض مقدّم المحتوى للتطبيق الذي ينسخ معرّف موارد منتظم (URI) إلى الحافظة معرّف ملف
AssetFileDescriptor
إذا كان بإمكانه تقديم نوع MIME هذا، ويُعرِض استثناءً إذا لم يكن بإمكانه ذلك.تعالج هذه الطريقة الأقسام الفرعية من الملفات. ويمكنك استخدامها لقراءة مواد العرض التي نسخها مقدّم المحتوى إلى الحافظة.
-
openAssetFile()
-
هذه الطريقة هي شكل أكثر عمومية من
openTypedAssetFile()
. ولا يفرِّط في قراءة أنواع MIME المسموح بها، ولكن يمكنه قراءة الأقسام الفرعية من الملفات. -
openFile()
-
هذا شكل أكثر عمومية من
openAssetFile()
. لا يمكنه قراءة الأقسام الفرعية من الملفات.
يمكنك اختياريًا استخدام الطريقة
openPipeHelper()
مع طريقة وصف الملف. يتيح ذلك لتطبيق اللصق قراءة بيانات البث في سلسلسة مهام
في الخلفية باستخدام أنبوب. لاستخدام هذه الطريقة، نفِّذ واجهة
ContentProvider.PipeDataWriter
.
تصميم وظيفة فعّالة للنسخ واللصق
لتصميم وظيفة فعالة للنسخ واللصق في تطبيقك، يجب مراعاة النقاط التالية:
- لا يمكن أن يتضمّن هذا القسم أكثر من مقطع واحد في أي وقت. يؤدي إجراء عملية نسخ جديدة من خلال أي تطبيق في النظام إلى استبدال المقطع السابق. بما أنّ المستخدم قد ينتقل بعيدًا عن تطبيقك وينسخ المحتوى قبل العودة، لا يمكنك افتراض أنّ الحافظة تحتوي على المقطع الذي نسخه المستخدم سابقًا في تطبيقك.
-
الغرض المقصود من استخدام عناصر
ClipData.Item
متعددة لكل مقطع هو السماح بنسخ ولصق اختيارات متعددة بدلاً من أشكال مختلفة لإشارة إلى اختيار واحد. عادةً ما تريد أن يكون الشكل نفسه لجميعClipData.Item
العناصر في المقطع. وهذا يعني أنّه يجب أن تكون جميعها نصًا بسيطًا أو محتوى URI أوIntent
، وألا تكون مختلطة. -
عند تقديم البيانات، يمكنك تقديم تمثيلات مختلفة لتنسيق MIME. أضِف أنواع MIME
المتوافقة مع تطبيقك إلى
ClipDescription
، ثم نفِّذ أنواع MIME في موفِّر المحتوى. -
عند الحصول على بيانات من الحافظة، يكون تطبيقك مسؤولاً عن التحقّق من
أنواع MIME المتاحة ثم تحديد النوع الذي سيتم استخدامه، إن توفّر. حتى إذا كان هناك مقطع في الحافظة وطلب المستخدم لصقه، ليس مطلوبًا من تطبيقك لصقه. الصِق المحتوى إذا كان نوع MIME متوافقًا. يمكنك تحويل البيانات
في الحافظة إلى نص باستخدام
coerceToText()
. إذا كان تطبيقك يتيح استخدام أكثر من نوع واحد من أنواع MIME المتاحة، يمكنك السماح للمستخدم باختيار النوع الذي يريده.