Android, kopyalama ve yapıştırma için güçlü bir pano tabanlı çerçeve sağlar. Metin dizeleri, karmaşık veri yapıları, metin ve ikili akış verileri ve uygulama öğeleri gibi basit ve karmaşık veri türlerini destekler. Basit metin verileri doğrudan panoda saklanırken, karmaşık veriler de yapıştırma uygulamasının içerik sağlayıcıyla çözdüğü bir referans olarak saklanır. Kopyalama ve yapıştırma hem uygulama içinde hem de çerçeveyi uygulayan uygulamalar arasında çalışır.
Çerçevenin bir kısmı içerik sağlayıcıları kullandığından bu belgede, İçerik sağlayıcılar bölümünde açıklanan Android Content Provider API hakkında biraz bilgi sahibi olduğunuz varsayılmaktadır.
Kullanıcılar panoya içerik kopyalarken geri bildirim bekler. Bu nedenle, kopyalama ve yapıştırma işlevine güç veren çerçeveye ek olarak Android, Android 13 (API düzeyi 33) ve sonraki sürümlerde kopyalama yaparken kullanıcılara varsayılan bir kullanıcı arayüzü gösterir. Bu özellik nedeniyle, yinelenen bildirimler riski vardır. Bu uç durum hakkında daha fazla bilgiyi Yinelenen bildirimlerden kaçınma bölümünden edinebilirsiniz.
Android 12L (API düzeyi 32) ve önceki sürümlerde kopyalama yaparken kullanıcılara manuel olarak geri bildirim sağlayın. Bu dokümanda bununla ilgili önerilere göz atın.
Pano çerçevesi
Pano çerçevesini kullandığınızda, verileri bir klip nesnesine yerleştirin ve ardından klip nesnesini sistem genelindeki panoya yerleştirin. Klip nesnesi şu üç biçimden birinde olabilir:
- Text
- Metin dizesi. Dizeyi doğrudan klip nesnesine, daha sonra da panoya yerleştirin. Dizeyi yapıştırmak için klip nesnesini panodan alın ve dizeyi uygulamanızın depolama alanına kopyalayın.
- URI
-
Herhangi bir URI biçimini temsil eden
Uri
nesnesi. Bu öncelikle bir içerik sağlayıcıdan karmaşık verilerin kopyalanması içindir. Verileri kopyalamak için klip nesnesineUri
nesnesi, klip nesnesini ise panoya yerleştirin. Verileri yapıştırmak için klip nesnesini alın,Uri
nesnesini alın, içerik sağlayıcı gibi bir veri kaynağına çözümleyin ve kaynaktaki verileri uygulamanızın depolama alanına kopyalayın. - Amaç
-
Intent
. Bu özellik, uygulama kısayollarının kopyalanmasını destekler. Verileri kopyalamak için birIntent
oluşturun, bunu bir klip nesnesine yerleştirin ve klip nesnesini panoya yerleştirin. Verileri yapıştırmak için klip nesnesini alın ve ardındanIntent
nesnesini uygulamanızın bellek alanına kopyalayın.
Pano aynı anda yalnızca bir klip nesnesi tutar. Bir uygulama panoya bir klip nesnesi yerleştirdiğinde, önceki klip nesnesi kaybolur.
Kullanıcıların uygulamanıza veri yapıştırmasına izin vermek istiyorsanız tüm veri türlerini işlemeniz gerekmez. Kullanıcılara yapıştırma seçeneği sunmadan önce panodaki verileri inceleyebilirsiniz. Klip nesnesi, belirli bir veri biçimine sahip olmanın yanı sıra, hangi MIME türlerinin mevcut olduğunu bildiren meta veriler de içerir. Bu meta veriler, uygulamanızın pano verileriyle faydalı bir şeyler yapıp yapamayacağına karar vermenize yardımcı olur. Örneğin, öncelikli olarak metin işleyen bir uygulamanız varsa URI veya amaç içeren klip nesnelerini göz ardı etmek isteyebilirsiniz.
Ayrıca, panodaki veri biçiminden bağımsız olarak kullanıcıların metin yapıştırmasına da izin verebilirsiniz. Bunu yapmak için pano verilerini metin gösterimine zorlayın, ardından bu metni yapıştırın. Bu, Panoyu metne yönlendirme bölümünde açıklanmaktadır.
Pano dersleri
Bu bölümde, pano çerçevesi tarafından kullanılan sınıflar açıklanmaktadır.
Pano Yöneticisi
Android sistem panosu, genel ClipboardManager
sınıfıyla gösterilir.
Bu sınıfı doğrudan somutlaştırmayın. Bunun yerine, getSystemService(CLIPBOARD_SERVICE)
komutunu çağırarak referans alabilirsiniz.
ClipData, ClipData.Item ve ClipDescription
Panoya veri eklemek için verilerin ve verilerin açıklamasını içeren bir ClipData
nesnesi oluşturun. Panoda her defasında bir ClipData
tutulur. Bir ClipData
, bir ClipDescription
nesnesi ve bir veya daha fazla ClipData.Item
nesne içerir.
ClipDescription
nesnesi, kliple ilgili meta verileri içerir. Özellikle, klibin verileri için bir dizi kullanılabilir MIME türü içerir. Buna ek olarak, Android 12 (API düzeyi 31) ve sonraki sürümlerde meta veriler nesnenin stilize edilmiş metin içerip içermediği ve nesnedeki metin türü hakkında bilgiler içerir.
Panoya bir klip yerleştirdiğinizde, bu bilgiler uygulamalara yapıştırılarak kullanılabilir. Bu bilgiler, uygulamaların klip verilerini işleyip işleyemediğini inceleyebilir.
Bir ClipData.Item
nesnesi metin, URI veya amaç verilerini içerir:
- Text
-
CharSequence
. - URI
-
Uri
. Bu genellikle bir içerik sağlayıcı URI'sı içerir ancak herhangi bir URI'ye izin verilir. Verileri sağlayan uygulama, URI'yı panoya yerleştirir. Verileri yapıştırmak isteyen uygulamalar panodan URI'yı alır ve içerik sağlayıcıya ya da başka bir veri kaynağına erişmek ve verileri almak için kullanır. - Amaç
-
Intent
. Bu veri türü, uygulama kısayolunu panoya kopyalamanıza olanak tanır. Böylece kullanıcılar, kısayolu daha sonra kullanmak üzere uygulamalarına yapıştırabilir.
Bir klibe birden fazla ClipData.Item
nesnesi ekleyebilirsiniz. Bu, kullanıcıların birden fazla seçimi
kopyalayıp tek bir klip olarak yapıştırmasına olanak tanır. Örneğin, kullanıcının aynı anda birden fazla öğe seçmesine olanak tanıyan bir liste widget'ınız varsa tüm öğeleri aynı anda panoya kopyalayabilirsiniz. Bunu yapmak için her liste öğesi için ayrı bir ClipData.Item
oluşturun ve daha sonra ClipData.Item
nesnelerini ClipData
nesnesine ekleyin.
ClipData kolaylık yöntemleri
ClipData
sınıfı, tek bir ClipData.Item
nesnesi ve basit bir ClipDescription
nesnesiyle ClipData
nesnesi oluşturmak için statik kolaylık yöntemleri sağlar:
-
newPlainText(label, text)
- Tek
ClipData.Item
nesnesinin metin dizesi içeren birClipData
nesnesi döndürür.ClipDescription
nesnesinin etiketilabel
olarak ayarlandı.ClipDescription
içindeki tek MIME türüMIMETYPE_TEXT_PLAIN
.Metin dizesinden klip oluşturmak için
newPlainText()
komutunu kullanın. -
newUri(resolver, label, URI)
- Tek
ClipData.Item
nesnesinin URI içeren birClipData
nesnesi döndürür.ClipDescription
nesnesinin etiketilabel
olarak ayarlandı. URI bir içerik URI'siyse (Uri.getScheme()
,content:
değerini döndürürse) yöntem, kullanılabilir MIME türlerini içerik sağlayıcıdan almak içinresolver
içinde sağlananContentResolver
nesnesini kullanır. Daha sonra bunlarıClipDescription
içinde depolar.content:
URI'sı olmayan bir URI için yöntem, MIME türünüMIMETYPE_TEXT_URILIST
olarak ayarlar.Bir URI'den, özellikle de
content:
URI'sından klip oluşturmak içinnewUri()
öğesini kullanın. -
newIntent(label, intent)
- Tek
ClipData.Item
nesnesiIntent
içeren birClipData
nesnesi döndürür.ClipDescription
nesnesinin etiketilabel
olarak ayarlandı. MIME türüMIMETYPE_TEXT_INTENT
olarak ayarlandı.Intent
nesnesinden klip oluşturmak içinnewIntent()
komutunu kullanın.
Pano verilerini metne dönüştürme
Uygulamanız yalnızca metin işliyor olsa bile metin olmayan verileri ClipData.Item.coerceToText()
yöntemiyle dönüştürerek panodan kopyalayabilirsiniz.
Bu yöntem, ClipData.Item
içindeki verileri metne dönüştürür ve CharSequence
döndürür. ClipData.Item.coerceToText()
işlevinin döndürdüğü değer, ClipData.Item
öğesindeki veri biçimine bağlıdır:
- Text
-
ClipData.Item
metinse (getText()
null değilse) coerceToText() metni döndürür. - URI
-
ClipData.Item
bir URI ise (yanigetUri()
null değilse)coerceToText()
bunu içerik URI'si olarak kullanmaya çalışır.- URI bir içerik URI'sı ise ve sağlayıcı bir metin akışı döndürebiliyorsa
coerceToText()
bir metin akışı döndürür. - URI bir içerik URI'sı olmasına rağmen sağlayıcı bir metin akışı sunmuyorsa
coerceToText()
, URI'nın bir temsilini döndürür. Temsil,Uri.toString()
tarafından döndürülenle aynıdır. - URI bir içerik URI'si değilse
coerceToText()
, URI'nın bir gösterimini döndürür. Temsil,Uri.toString()
tarafından döndürülenle aynıdır.
- URI bir içerik URI'sı ise ve sağlayıcı bir metin akışı döndürebiliyorsa
- Amaç
ClipData.Item
birIntent
ise (yanigetIntent()
null değilse)coerceToText()
bunu bir Intent URI'sına dönüştürür ve döndürür. Temsil,Intent.toUri(URI_INTENT_SCHEME)
tarafından döndürülenle aynıdır.
Pano çerçevesi, Şekil 2'de özetlenmiştir. Bir uygulama, verileri kopyalamak için ClipboardManager
genel panosuna ClipData
nesnesi yerleştirir. ClipData
, bir veya daha fazla ClipData.Item
nesnesi ve bir ClipDescription
nesnesi içerir. Uygulama, verileri yapıştırmak için ClipData
bilgisini alır, MIME türünü ClipDescription
'dan ve verileri ClipData.Item
veya ClipData.Item
tarafından başvurulan içerik sağlayıcıdan alır.
Panoya kopyala
Verileri panoya kopyalamak için genel ClipboardManager
nesnesini tutun, bir ClipData
nesnesi oluşturun ve buna ClipDescription
ile bir veya daha fazla ClipData.Item
nesnesi ekleyin. Ardından, biten ClipData
nesnesini ClipboardManager
nesnesine ekleyin. Bu, aşağıdaki prosedürde daha ayrıntılı bir şekilde açıklanmaktadır:
- İçerik URI'sı kullanarak veri kopyalıyorsanız bir içerik sağlayıcı ayarlayın.
- Sistem panosunu alın:
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);
-
Verileri yeni bir
ClipData
nesnesine kopyalayın:-
Metin için
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 için
Bu snippet, sağlayıcının içerik URI'sına bir kayıt kimliği kodlayarak bir URI oluşturur. Bu teknik, URI'de bir tanımlayıcıyı kodlama bölümünde daha ayrıntılı olarak ele alınmıştır.
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);
-
Amacınız için
Bu snippet, bir uygulama için
Intent
oluşturur ve daha sonra bunu klip nesnesine yerleştirir: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);
-
Metin için
-
Yeni klip nesnesini panoya yerleştirin:
Kotlin
// Set the clipboard's primary clip. clipboard.setPrimaryClip(clip)
Java
// Set the clipboard's primary clip. clipboard.setPrimaryClip(clip);
Panoya kopyalarken geri bildirim sağla
Kullanıcılar, uygulamalar panoya içerik kopyaladığında görsel geri bildirim bekler. Bu işlem, Android 13 ve sonraki sürümlerdeki kullanıcılar için otomatik olarak gerçekleştirilir ancak önceki sürümlerde manuel olarak uygulanması gerekir.
Android 13'ten itibaren, içerik panoya eklendiğinde sistem standart bir görsel onay gösterir. Yeni onay aşağıdaki işlemleri gerçekleştirir:
- İçeriğin başarıyla kopyalandığını onaylar.
- Kopyalanan içeriğin önizlemesini sağlar.
Android 12L (API düzeyi 32) ve önceki sürümlerde kullanıcılar içeriği başarılı bir şekilde mi yoksa neleri kopyaladıklarından emin olamayabilir. Bu özellik, kopyalama işleminden sonra uygulamalar tarafından gösterilen çeşitli bildirimleri standart hale getirir ve kullanıcılara pano üzerinde daha fazla kontrol sunar.
Yinelenen bildirimlerden kaçının
Android 12L (API düzeyi 32) ve önceki sürümlerde, kopyalama işleminden sonra Toast
veya Snackbar
gibi bir widget kullanarak görsel, uygulama içi geri bildirim göndererek kullanıcıları başarılı bir şekilde kopyalama işlemi yaptıklarında uyarmanızı öneririz.
Android 13 ve sonraki sürümlerde, bilgilerin yinelenen şekilde gösterilmesini önlemek için uygulama içi kopyadan sonra gösterilen durum bildirimlerini veya atıştırmalık çubuklarını kaldırmanızı kesinlikle öneririz.
Aşağıda, bunun nasıl uygulanacağına ilişkin bir örnek verilmiştir:
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() }
Panoya hassas içerik ekleme
Uygulamanız, kullanıcıların şifreler veya kredi kartı bilgileri gibi hassas içerikleri panoya kopyalamalarına izin veriyorsa ClipboardManager.setPrimaryClip()
işlevini çağırmadan önce ClipData
içinde ClipDescription
için bayrak eklemeniz gerekir. Bu işaretin eklenmesi, Android 13 ve sonraki sürümlerde kopyalanan içeriğin görsel onayında hassas içeriğin görünmesini engeller.
Hassas içerikleri işaretlemek için ClipDescription
öğesine fazladan bir boole ekleyin. Hedeflenen API düzeyi ne olursa olsun tüm uygulamalar bunu yapmalıdır.
// 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) } }
Panodan yapıştır
Daha önce açıklandığı gibi, genel pano nesnesini alarak, klip nesnesini alarak, verilerine bakarak ve mümkünse verileri klip nesnesinden kendi depolama alanınıza kopyalayarak panodan veri yapıştırın. Bu bölümde, üç pano verisi biçiminin nasıl yapıştırılacağı ayrıntılı olarak açıklanmaktadır.
Düz metin yapıştır
Düz metni yapıştırmak için genel panoyu alın ve düz metin döndürebildiğini doğrulayın. Ardından klip nesnesini alın ve aşağıdaki prosedürde açıklandığı gibi getText()
öğesini kullanarak metnini kendi depolama alanınıza kopyalayın:
getSystemService(CLIPBOARD_SERVICE)
kullanarak genelClipboardManager
nesnesini alın. Ayrıca, yapıştırılan metni içerecek bir genel değişken bildirin:Kotlin
var clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager var pasteData: String = ""
Java
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); String pasteData = "";
- Geçerli etkinlikte "Yapıştır" seçeneğini etkinleştirmeniz mi yoksa devre dışı bırakmanız mı gerektiğini belirleyin. Panonun bir klip içerdiğini ve klibin temsil ettiği veri türünü işleyebileceğinizi doğrulayın:
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); }
- Panodaki verileri kopyalayın. Koddaki bu noktaya yalnızca "yapıştır" menü öğesi etkinse erişilebilir. Dolayısıyla, panonun düz metin içerdiğini varsayabilirsiniz. Bir metin dizesi veya düz metne işaret eden bir URI içerip içermediğinden emin olamazsınız.
Aşağıdaki kod snippet'i bunu test eder, ancak yalnızca düz metin işleme kodunu gösterir:
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; } }
İçerik URI'sından veri yapıştırma
ClipData.Item
nesnesi bir içerik URI'si içeriyorsa ve MIME türlerinden birini işleyebileceğinizi belirlerseniz bir ContentResolver
oluşturun ve verileri almak için uygun içerik sağlayıcı yöntemini çağırın.
Aşağıdaki prosedürde, panodaki içerik URI'sına dayanarak içerik sağlayıcıdan nasıl veri alınacağı açıklanmaktadır. Uygulamanın kullanabileceği bir MIME türünün sağlayıcıdan sunulup sunulmadığını kontrol eder.
-
Genel değişkeni, MIME türünü içerecek şekilde bildirin:
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";
- Genel panoyu al. Ayrıca içerik sağlayıcıya erişebilmek için bir içerik çözümleyici edinin:
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();
- Panodan birincil klibi alın ve içeriğini URI olarak alın:
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)
yöntemini çağırarak URI'nın bir içerik URI'si olup olmadığını test edin.Uri
geçerli bir içerik sağlayıcıya işaret etmiyorsa bu yöntem null değerini döndürür.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);
- İçerik sağlayıcının, uygulamanın anladığı bir MIME türünü destekleyip desteklemediğini test edin. İçeriyorsa verileri almak için
ContentResolver.query()
yöntemini çağırın. Döndürülen değerCursor
olur.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(); } } } }
İntent Yapıştır
Niyeti yapıştırmak için önce genel panoyu alın. Intent
içerip içermediğini görmek için ClipData.Item
nesnesini inceleyin. Ardından, amacı kendi depolama alanınıza kopyalamak için getIntent()
numaralı telefonu arayın. Aşağıdaki snippet bunu gösterir:
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. }
Uygulamanız pano verilerine eriştiğinde gösterilen sistem bildirimi
Android 12 (API düzeyi 31) ve sonraki sürümlerde, uygulamanız getPrimaryClip()
araması yaptığında sistem genellikle bir durum mesajı gösterir.
İletinin içindeki metin şu biçimdedir:
APP pasted from your clipboard
Uygulamanız aşağıdakilerden birini yaptığında sistem bir durum mesajı mesajı göstermez:
ClipData
uygulamasına kendi uygulamanızdan erişir.- Belirli bir uygulama üzerinden
ClipData
uygulamasına sürekli olarak erişiyor. Durum mesajı, yalnızca uygulamanız söz konusu uygulamadaki verilere ilk kez eriştiğinde görünür. - Klip nesnesinin meta verilerini alır (örneğin,
getPrimaryClip()
yerinegetPrimaryClipDescription()
yöntemini çağırarak).
Karmaşık verileri kopyalamak için içerik sağlayıcıları kullanma
İçerik sağlayıcılar, veritabanı kayıtları veya dosya akışları gibi karmaşık verilerin kopyalanmasını destekler. Verileri kopyalamak için panoya bir içerik URI'si yerleştirin. Uygulamalar daha sonra panodan bu URI'yı alır ve veritabanı verilerini veya dosya akışı açıklayıcılarını almak için kullanır.
Yapıştırma uygulaması, verileriniz için yalnızca içerik URI'sına sahip olduğundan hangi veri parçasının alınacağını bilmesi gerekir. Bu bilgileri, URI'nın kendisinde veriler için bir tanımlayıcı kodlayarak veya kopyalamak istediğiniz verileri döndüren benzersiz bir URI sağlayabilirsiniz. Hangi teknik verilerin düzenleneceğine bağlıdır.
Aşağıdaki bölümlerde URI'lerin nasıl oluşturulacağı, karmaşık verilerin nasıl sağlanacağı ve dosya akışlarının nasıl sağlanacağı açıklanmaktadır. Açıklamalarda, içerik sağlayıcı tasarımının genel ilkeleri hakkında bilgi sahibi olduğunuz varsayılır.
Bir tanımlayıcıyı URI'da kodlama
Verileri bir URI ile panoya kopyalamak için yararlı bir teknik, URI'nın kendisinde veriler için bir tanımlayıcı kodlamaktır. Daha sonra içerik sağlayıcınız tanımlayıcıyı URI'dan alabilir ve verileri almak için kullanabilir. Yapıştırma uygulamasının, tanımlayıcının var olduğunu bilmesi gerekmez. Bunun için panodan "referansı" (URI ile tanımlayıcı) almanız, içerik sağlayıcınıza vermeniz ve verileri geri almanız yeterlidir.
Bir tanımlayıcıyı genellikle URI'nın sonuyla birleştirerek içerik URI'sına kodlarsınız. Örneğin, sağlayıcı URI'nızı aşağıdaki dize olarak tanımladığınızı varsayalım:
"content://com.example.contacts"
Bu URI üzerine bir ad kodlamak istiyorsanız şu kod snippet'ini kullanın:
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);
Zaten bir içerik sağlayıcı kullanıyorsanız URI'nın kopyalama için olduğunu belirten yeni bir URI yolu eklemek isteyebilirsiniz. Örneğin, zaten aşağıdaki URI yollarına sahip olduğunuzu varsayalım:
"content://com.example.contacts/people" "content://com.example.contacts/people/detail" "content://com.example.contacts/people/images"
URI'leri kopyalamak için başka bir yol ekleyebilirsiniz:
"content://com.example.contacts/copying"
Daha sonra, kalıp eşleştirmeyle bir "kopya" URI'sını algılayabilir ve bunu, kopyalama ve yapıştırma için özel kodla işleyebilirsiniz.
Kodlama tekniğini, verilerinizi düzenlemek için zaten bir içerik sağlayıcı, dahili veritabanı veya dahili tablo kullanıyorsanız normal şekilde kullanırsınız. Bu gibi durumlarda, kopyalamak istediğiniz birden fazla veri parçası ve muhtemelen her bir parça için benzersiz bir tanımlayıcınız olur. Yapıştırma uygulamasından yapılan bir sorguya yanıt olarak, verileri tanımlayıcısına göre arayıp döndürebilirsiniz.
Birden çok veri parçanız yoksa muhtemelen bir tanımlayıcı kodlamanız gerekmez. Sağlayıcınıza özgü bir URI kullanabilirsiniz. Bir sorguya yanıt olarak, sağlayıcınız şu anda içerdiği verileri döndürür.
Veri yapılarını kopyalama
ContentProvider
bileşeninin bir alt sınıfı olarak karmaşık verileri kopyalayıp yapıştırmak için bir içerik sağlayıcı ayarlayın. Panoya yerleştirdiğiniz URI'yı, tam olarak sağlamak istediğiniz kaydı işaret edecek şekilde kodlayın. Ayrıca başvurunuzun mevcut durumunu da göz önünde bulundurun:
- Halihazırda bir içerik sağlayıcınız varsa işlevselliğini ekleyebilirsiniz. Veri yapıştırmak isteyen uygulamalardan gelen URI'leri işlemek için
query()
yöntemini değiştirmeniz gerekebilir. Muhtemelen yöntemi bir "kopya" URI kalıbını işleyecek şekilde değiştirmek istersiniz. - Uygulamanız dahili bir veritabanına sahipse bu veritabanından kopyalamayı kolaylaştırmak için veritabanını bir içerik sağlayıcısına taşımak isteyebilirsiniz.
- Veritabanı kullanmıyorsanız tek amacı panodan yapıştırma yapan uygulamalara veri sunmak olan basit bir içerik sağlayıcı uygulayabilirsiniz.
İçerik sağlayıcıda, en azından aşağıdaki yöntemleri geçersiz kılın:
-
query()
- Yapıştırılan uygulamalar, bu yöntemi panoya yerleştirdiğiniz URI ile kullanarak verilerinizi alabildiğini varsayar. Kopyalamayı desteklemek için bu yöntemin, özel bir "kopya" yolu içeren URI'leri algılamasını sağlayın. Uygulamanız bunun ardından panoya yerleştirmek üzere kopyalama yolunu ve kopyalamak istediğiniz tam kaydın işaretçisini içeren bir "kopya" URI'sı oluşturabilir.
-
getType()
- Bu yöntem, kopyalamak istediğiniz veriler için MIME türlerini döndürmelidir.
newUri()
yöntemi, MIME türlerini yeniClipData
nesnesine yerleştirmek içingetType()
yöntemini çağırır.Karmaşık verilere yönelik MIME türleri, İçerik sağlayıcılarda açıklanmıştır.
Diğer içerik sağlayıcı yöntemlerinden (ör.
insert()
veya
update()
) birini kullanmanız gerekmez.
Yapıştırma uygulamalarının yalnızca desteklenen MIME türlerinizi alması ve sağlayıcınızdan veri kopyalaması yeterlidir.
Bu yöntemleri zaten kullanıyorsanız kopyalama işlemlerini etkilemezler.
Aşağıdaki snippet'lerde karmaşık verileri kopyalamak için uygulamanızı nasıl ayarlayacağınız gösterilmektedir:
-
Uygulamanızın genel sabit değerlerinde, bir temel URI dizesi ve verileri kopyalamak için kullandığınız URI dizelerini tanımlayan bir yol bildirin. Kopyalanan veriler için de bir MIME türü bildirin.
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";
- Kullanıcıların veri kopyaladığı etkinlik bölümünde, verileri panoya kopyalamak için kodu ayarlayın.
Kopyalama isteğine yanıt olarak URI'yi panoya yerleştirin.
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);
-
İçerik sağlayıcınızın genel kapsamında, bir URI eşleştirici oluşturun ve panoya yerleştirdiğiniz URI'lerle eşleşen bir URI kalıbı ekleyin.
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()
yöntemini ayarlayın. Bu yöntem, kodlama şeklinize bağlı olarak farklı URI kalıplarını işleyebilir ancak yalnızca pano kopyalama işleminin kalıbı gösterilir.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. ... }
-
Kopyalanan veriler için uygun bir MIME türü döndürecek
getType()
yöntemini ayarlayın: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); ... } }
İçerik URI'sinden veri yapıştırma bölümünde, panodan içerik URI'sinin nasıl alınacağı ve verileri almak ve yapıştırmak için nasıl kullanılacağı açıklanmaktadır.
Veri akışlarını kopyala
Büyük miktarlarda metin ve ikili verileri akış olarak kopyalayıp yapıştırabilirsiniz. Veriler aşağıdaki gibi formlara sahip olabilir:
- Asıl cihazda depolanan dosyalar
- Yuvalardan akışlar
- Bir sağlayıcının temel veritabanı sisteminde depolanan büyük miktarda veri
Veri akışları için bir içerik sağlayıcı, verilerine Cursor
nesnesi yerine AssetFileDescriptor
gibi bir dosya tanımlayıcı nesne ile erişim sağlar. Yapıştırma uygulaması, veri akışını bu dosya açıklayıcıyı kullanarak okur.
Uygulamanızı bir veri akışını sağlayıcıyla kopyalayacak şekilde ayarlamak için aşağıdaki adımları uygulayın:
-
Panoya koyduğunuz veri akışı için bir içerik URI'si oluşturun. Bunun için kullanabileceğiniz seçenekler şunlardır:
- URI'de tanımlayıcı kodlama bölümünde açıklandığı gibi, URI'ye veri akışı tanımlayıcısı kodlayın ve ardından sağlayıcınızda tanımlayıcılar ile ilgili akış adını içeren bir tabloyu saklayın.
- Akış adını doğrudan URI üzerinde kodlayın.
- Her zaman sağlayıcıdan geçerli akışı döndüren benzersiz bir URI kullanın. Bu seçeneği kullanırsanız, URI'yı kullanarak akışı panoya her kopyaladığınızda sağlayıcınızı farklı bir akışı işaret edecek şekilde güncellemeyi unutmayın.
- Sunmayı planladığınız her veri akışı türü için bir MIME türü sağlayın. Yapıştırılan uygulamalar, verileri panoya yapıştırıp yapıştıramayacaklarını belirlemek için bu bilgilere ihtiyaç duyar.
- Akış için dosya tanımlayıcısı döndüren
ContentProvider
yöntemlerinden birini uygulayın. Tanımlayıcıları içerik URI'sinde kodluyorsanız hangi akışın açılacağını belirlemek için bu yöntemi kullanın. - Veri akışını panoya kopyalamak için içerik URI'sini oluşturun ve panoya yerleştirin.
Bir uygulama, veri akışını yapıştırmak için klibi panodan alır, URI'yı alır ve akışı açan bir ContentResolver
dosya açıklayıcı yöntemine yapılan çağrıda bunu kullanır. ContentResolver
yöntemi, ilgili ContentProvider
yöntemini içerik URI'sına iletir. Sağlayıcınız, dosya açıklayıcıyı ContentResolver
yöntemine döndürür. Yapıştırma uygulaması, verileri akıştan okuma sorumluluğuna sahiptir.
Aşağıdaki listede, içerik sağlayıcı için en önemli dosya tanımlayıcı yöntemleri gösterilmektedir. Bunların her biri, yöntem adına "Descriptor" dizesi eklenmiş olan karşılık gelen bir ContentResolver
yöntemine sahiptir. Örneğin, openAssetFile()
analogunun ContentResolver
analogu openAssetFileDescriptor()
olur.
-
openTypedAssetFile()
-
Bu yöntem yalnızca sağlanan MIME türünün sağlayıcı tarafından desteklenmesi durumunda bir öğe dosyası açıklayıcısı döndürür. Arayan (yapıştırma işlemini yapan uygulama) MIME türü kalıbı sağlar. URI'yı panoya kopyalayan uygulamanın içerik sağlayıcısı, söz konusu MIME türünü sağlayabiliyorsa bir
AssetFileDescriptor
dosya tanıtıcısı döndürür, sağlayamadığında ise bir istisna oluşturur.Bu yöntem dosyaların alt bölümlerini işler. İçerik sağlayıcının panoya kopyaladığı öğeleri okumak için bu özelliği kullanabilirsiniz.
-
openAssetFile()
-
Bu yöntem,
openTypedAssetFile()
işleminin daha genel bir biçimidir. İzin verilen MIME türlerini filtrelemez ancak dosyaların alt bölümlerini okuyabilir. -
openFile()
-
Bu,
openAssetFile()
için daha genel bir biçimdir. Dosyaların alt bölümlerini okuyamaz.
İsteğe bağlı olarak
openPipeHelper()
yöntemini dosya açıklayıcı yönteminizle kullanabilirsiniz. Bu, yapıştırma uygulamasının bir arka plan iş parçacığındaki akış verilerini bir dikey çizgi kullanarak okumasını sağlar. Bu yöntemi kullanmak için ContentProvider.PipeDataWriter
arayüzünü uygulayın.
Etkili kopyalama ve yapıştırma işlevleri tasarlayın
Uygulamanız için etkili kopyalama ve yapıştırma işlevleri tasarlamak için şu noktaları göz önünde bulundurun:
- Panoda herhangi bir zamanda yalnızca bir klip gösterilir. Sistemdeki herhangi bir uygulama tarafından gerçekleştirilen yeni bir kopyalama işlemi önceki klibin üzerine yazılır. Kullanıcı uygulamanızdan ayrılıp geri dönmeden önce kopyalayabileceğinden, panonun, kullanıcının daha önce sizin uygulamanızda kopyaladığı klibi içerdiğini varsayamazsınız.
-
Klip başına birden fazla
ClipData.Item
nesnesinin amacı, tek bir seçime farklı referans biçimleri yerine birden fazla seçimin kopyalanıp yapıştırılmasını desteklemektir. Genellikle bir klipteki tümClipData.Item
nesnelerinin aynı biçimde olmasını istersiniz. Yani tümünün basit metin, içerik URI veyaIntent
olması ve karma olmaması gerekir. -
Veri sağlarken farklı MIME temsilleri sunabilirsiniz. Desteklediğiniz MIME türlerini
ClipDescription
öğesine ekleyin, ardından MIME türlerini içerik sağlayıcınıza uygulayın. -
Panodan veri aldığınızda, kullanılabilir MIME türlerini kontrol etmek ve varsa hangisinin kullanılacağına karar vermek uygulamanızın sorumluluğundadır. Panoda klip olsa bile kullanıcı yapıştırma isteğinde bulunsa bile uygulamanızın bu yapıştırma işlemini yapması gerekmez. MIME türü uyumluysa yapıştırma işlemini yapın.
coerceToText()
kullanarak panodaki verileri metne dönüştürmeye zorlayabilirsiniz. Uygulamanız mevcut MIME türlerinden birden fazlasını destekliyorsa kullanıcının hangisinin kullanılacağını seçmesine izin verebilirsiniz.