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 ile uygulama öğeleri dahil olmak üzere basit ve karmaşık veri türlerini destekler. Basit metin verileri doğrudan panoda saklanırken karmaşık veriler, yapıştırma uygulamasının içerik sağlayıcıyla çözdüğü bir referans olarak saklanır. Kopyalama ve yapıştırma işlemleri hem bir uygulama içinde hem de çerçeveyi uygulayan uygulamalar arasında çalışır.
Çerçevenin bir bölümünde içerik sağlayıcılar kullanıldığından bu belgede, İçerik sağlayıcılar bölümünde açıklanan Android Content Provider API hakkında bilgi sahibi olduğunuz varsayılmaktadır.
Kullanıcılar, içeriği panoya kopyalarken geri bildirim almayı bekler. Bu nedenle, kopyalama ve yapıştırma işlemlerini destekleyen çerçeveye ek olarak Android, Android 13 (API düzeyi 33) ve sonraki sürümlerde kopyalama işlemi sırasında kullanıcılara varsayılan bir kullanıcı arayüzü gösterir. Bu özellik nedeniyle, bildirimlerin yinelenme riski vardır. Bu uç durum hakkında daha fazla bilgiyi Yinelenen bildirimlerden kaçınma bölümünde bulabilirsiniz.

Android 12L (API düzeyi 32) ve daha düşük sürümlerde kopyalama işlemi yapıldığında kullanıcılara manuel olarak geri bildirim sağlama. Bu belgede bununla ilgili önerileri inceleyin.
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 üç biçimden birinde olabilir:
- Metin
- Metin dizesi. Dizeyi doğrudan klip nesnesine yerleştirin. Ardından, bu nesneyi panoya yerleştirin. Dizeyi yapıştırmak için pano 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 işlev, öncelikli olarak bir içerik sağlayıcıdan karmaşık verileri kopyalamak için kullanılır. Verileri kopyalamak için birUri
nesnesini bir pano nesnesine yerleştirin ve pano nesnesini 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 verileri kaynaktan uygulamanızın depolama alanına kopyalayın. - Amaç
-
An
Intent
. Bu, uygulama kısayollarının kopyalanmasını destekler. Verileri kopyalamak için birIntent
oluşturun, bunu bir pano nesnesine yerleştirin ve pano nesnesini panoya yerleştirin. Verileri yapıştırmak için klip nesnesini alın veIntent
nesnesini uygulamanızın bellek alanına kopyalayın.
Pano, tek seferde yalnızca bir klip nesnesi tutar. Bir uygulama, pano nesnesini panoya koyduğunda önceki pano 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ğini sunmadan önce panodaki verileri inceleyebilirsiniz. Klip nesnesi, belirli bir veri biçimine sahip olmanın yanı sıra hangi MIME türlerinin kullanılabildiğini belirten meta veriler de içerir. Bu meta veriler, uygulamanızın panodaki verilerle yararlı bir işlem yapıp yapamayacağına karar vermenize yardımcı olur. Örneğin, öncelikle metin işleyen bir uygulamanız varsa URI veya amaç içeren kırpma nesnelerini yoksaymak isteyebilirsiniz.
Ayrıca, kullanıcıların panodaki verilerin biçimine bakılmaksızın metin yapıştırmasına izin vermek isteyebilirsiniz. Bunu yapmak için pano verilerini metin gösterimine zorlayın ve bu metni yapıştırın. Bu durum, Panoyu metne dönüştürme bölümünde açıklanmıştır.
Pano sınıfları
Bu bölümde, pano çerçevesi tarafından kullanılan sınıflar açıklanmaktadır.
ClipboardManager
Android sistem panosu, genel ClipboardManager
sınıfıyla temsil edilir.
Bu sınıfı doğrudan başlatmayın. Bunun yerine, getSystemService(CLIPBOARD_SERVICE)
işlevini çağırarak referans alın.
ClipData, ClipData.Item ve ClipDescription
Pano'ya veri eklemek için verilerin açıklamasını ve verilerin kendisini içeren bir ClipData
nesnesi oluşturun. Panoda tek seferde bir ClipData
bulunur. Bir ClipData
, bir ClipDescription
nesnesi ve bir veya daha fazla ClipData.Item
nesnesi içerir.
ClipDescription
nesnesi, kliple ilgili meta verileri içerir. Bu nesne, özellikle klibin verileri için kullanılabilen MIME türlerinin bir dizisini içerir. Ayrıca, 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 koyduğunuzda bu bilgiler, klip verilerini işleyip işleyemeyeceklerini inceleyebilen yapıştırma uygulamaları tarafından kullanılabilir.
ClipData.Item
nesnesi metin, URI veya amaç verilerini içerir:
- Metin
-
A
CharSequence
. - URI
-
A
Uri
. Bu genellikle bir içerik sağlayıcı URI'si içerir ancak herhangi bir URI'ye izin verilir. Verileri sağlayan uygulama, URI'yi panoya yerleştirir. Verileri yapıştırmak isteyen uygulamalar, URI'yi panodan alır ve içerik sağlayıcıya veya başka bir veri kaynağına erişip verileri almak için kullanır. - Amaç
-
Bir
Intent
. Bu veri türü, uygulama kısayollarını panoya kopyalamanıza olanak tanır. Kullanıcılar daha sonra kullanmak üzere kısayolu uygulamalarına yapıştırabilir.
Bir klibe birden fazla ClipData.Item
nesnesi ekleyebilirsiniz. Bu özellik, kullanıcıların birden fazla seçimi tek bir klip olarak kopyalayıp 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 ardından 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
nesnesi metin dizesi içeren birClipData
nesnesi döndürür.ClipDescription
nesnesinin etiketilabel
olarak ayarlanmıştır.ClipDescription
içindeki tek MIME türüMIMETYPE_TEXT_PLAIN
.Metin dizesinden klip oluşturmak için
newPlainText()
simgesini kullanın. -
newUri(resolver, label, URI)
- Tek
ClipData.Item
nesnesi URI içeren birClipData
nesnesi döndürür.ClipDescription
nesnesinin etiketilabel
olarak ayarlanmıştır. URI bir içerik URI'si ise (yaniUri.getScheme()
content:
değerini döndürüyorsa) yöntem, içerik sağlayıcıdan kullanılabilir MIME türlerini almak içinresolver
içinde sağlananContentResolver
nesnesini kullanır. Ardından, bunlarıClipDescription
konumunda saklar.content:
URI'si olmayan bir URI için yöntem, MIME türünüMIMETYPE_TEXT_URILIST
olarak ayarlar.Bir URI'den (özellikle
newUri()
URI'si) klip oluşturmak içinnewUri()
simgesini kullanın.content:
-
newIntent(label, intent)
- Tek
ClipData.Item
nesnesiIntent
içeren birClipData
nesnesi döndürür.ClipDescription
nesnesinin etiketilabel
olarak ayarlanmıştır. MIME türüMIMETYPE_TEXT_INTENT
olarak ayarlanmıştır.Intent
nesnesinden klip oluşturmak içinnewIntent()
uygulamasını kullanın.
Pano verilerini metne dönüştürme
Uygulamanız yalnızca metinleri işlese bile, panodaki metin dışı verileri ClipData.Item.coerceToText()
yöntemiyle dönüştürerek kopyalayabilirsiniz.
Bu yöntem, ClipData.Item
içindeki verileri metne dönüştürür ve CharSequence
döndürür. ClipData.Item.coerceToText()
tarafından döndürülen değer, ClipData.Item
içindeki verilerin biçimine bağlıdır:
- Metin
-
ClipData.Item
metinse, yanigetText()
null değilse coerceToText() metni döndürür. - URI
-
ClipData.Item
bir URI ise (yanigetUri()
boş değilse)coerceToText()
bunu içerik URI'si olarak kullanmaya çalışır.- URI bir içerik URI'si ise ve sağlayıcı bir metin akışı döndürebiliyorsa,
coerceToText()
bir metin akışı döndürür. - URI bir içerik URI'si ise ancak sağlayıcı bir metin akışı sunmuyorsa,
coerceToText()
URI'nin bir gösterimini döndürür. Gösterim,Uri.toString()
tarafından döndürülenle aynıdır. - URI bir içerik URI'si değilse
coerceToText()
, URI'nin bir gösterimini döndürür. Gösterim,Uri.toString()
tarafından döndürülenle aynıdır.
- URI bir içerik URI'si ise ve sağlayıcı bir metin akışı döndürebiliyorsa,
- Amaç
- If
ClipData.Item
is anIntent
—that is, ifgetIntent()
isn't null—coerceToText()
converts it to an Intent URI and returns it. Gösterim,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 ClipData
nesnesini ClipboardManager
global panosuna yerleştirir. ClipData
, bir veya daha fazla ClipData.Item
nesnesi ve bir ClipDescription
nesnesi içeriyor. Bir uygulama, verileri yapıştırmak için ClipData
alır, MIME türünü ClipDescription
alır ve verileri ClipData.Item
veya ClipData.Item
tarafından belirtilen içerik sağlayıcıdan alır.

Panoya kopyalama
Verileri panoya kopyalamak için global ClipboardManager
nesnesinin tutamacını alın, bir ClipData
nesnesi oluşturun ve bu nesneye bir ClipDescription
ile bir veya daha fazla ClipData.Item
nesnesi ekleyin. Ardından, tamamlanmış ClipData
nesnesini ClipboardManager
nesnesine ekleyin. Bu durum, aşağıdaki prosedürde daha ayrıntılı olarak açıklanmıştır:
- Verileri içerik URI'si kullanarak kopyalıyorsanız bir içerik sağlayıcı oluşturun.
- Sistem panosunu alma:
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:-
Metinler 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'sine bir kayıt kimliği kodlayarak URI oluşturur. Bu teknik, URI'ye tanımlayıcı kodlama bölümünde daha ayrıntılı olarak ele alınmaktadı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);
-
Bir amaç için
Bu snippet, bir uygulama için
Intent
oluşturur ve ardından 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);
-
Metinler 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ğlama
Kullanıcılar, bir uygulama içeriği panoya kopyaladığında görsel geri bildirim bekler. Bu işlem, Android 13 ve sonraki sürümlerde otomatik olarak yapılır ancak önceki sürümlerde manuel olarak uygulanması gerekir.
Android 13'ten itibaren, panoya içerik eklendiğinde sistem standart bir görsel onay gösterir. Yeni onay şu işlemleri yapar:
- İçeriğin başarıyla kopyalandığını onaylar.
- Kopyalanan içeriğin önizlemesini gösterir.

Android 12L (API düzeyi 32) ve önceki sürümlerde kullanıcılar, içeriği başarıyla kopyalayıp kopyalamadıklarından veya ne kopyaladıklarından emin olmayabilir. Bu özellik, uygulamaların kopyalama işleminden sonra gösterdiği çeşitli bildirimleri standartlaştırır ve kullanıcılara pano üzerinde daha fazla kontrol olanağı sunar.
Yinelenen bildirimleri engelleme
Android 12L (API düzeyi 32) ve önceki sürümlerde, kullanıcılar kopyalama işlemini başarıyla tamamladığında görsel uygulama içi geri bildirimler vererek (ör. kopyalama işleminden sonra Toast
veya Snackbar
gibi bir widget kullanarak) uyarıda bulunmanızı öneririz.
Bilgilerin yinelenen şekilde gösterilmesini önlemek için Android 13 ve sonraki sürümlerde uygulama içi kopyalama işleminden sonra gösterilen kısa mesajları veya snackbar'ları kaldırmanızı önemle tavsiye ederiz.


Bunu nasıl uygulayacağınıza dair bir örneği aşağıda bulabilirsiniz:
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 şifre veya kredi kartı bilgileri gibi hassas içerikleri panoya kopyalamasına izin veriyorsa ClipDescription
öğesine ClipData
içinde ClipboardManager.setPrimaryClip()
çağrılmadan önce bir işaret eklemeniz gerekir. Bu işaretin eklenmesi, hassas içeriklerin Android 13 ve sonraki sürümlerde kopyalanan içeriğin görsel onayında görünmesini engeller.


Hassas içeriği işaretlemek için ClipDescription
öğesine bir boolean ekstra ekleyin. Hedeflenen API düzeyinden bağımsız olarak 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ırma
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 panodaki verileri yapıştırın. Bu bölümde, pano verilerinin üç biçiminin nasıl yapıştırılacağı ayrıntılı olarak açıklanmaktadır.
Düz metin yapıştırma
Düz metin yapıştırmak için genel panoyu alın ve düz metin döndürebildiğini doğrulayın. Ardından, aşağıdaki prosedürde açıklandığı gibi getText()
kullanarak klip nesnesini alın ve metnini kendi depolama alanınıza kopyalayın:
ClipboardManager
kullanarak globalClipboardManager
nesnesini alın.getSystemService(CLIPBOARD_SERVICE)
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 = "";
- Mevcut etkinlikte "yapıştır" seçeneğini etkinleştirmeniz veya devre dışı bırakmanız gerekip gerekmediğini belirleyin. Pano, bir klip içerdiğinden ve klip tarafından temsil edilen veri türünü işleyebildiğinizden emin olun:
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); }
- Verileri panodan kopyalayın. Koddaki bu noktaya yalnızca "yapıştır" menü öğesi etkinleştirilmişse ulaşılabilir. Bu nedenle, panoda düz metin olduğunu varsayabilirsiniz. Henüz düz metne işaret eden bir metin dizesi veya URI içerip içermediğini bilmiyorsunuz.
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'sinden veri yapıştırma
ClipData.Item
nesnesi bir içerik URI'si içeriyorsa ve MIME türlerinden birini işleyebileceğinizi belirlediyseniz 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'sine göre bir 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ıda mevcut olup olmadığını kontrol eder.
-
MIME türünü içerecek bir genel değişken 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 alma Ayrıca, içerik sağlayıcıya erişebilmeniz için bir içerik çözümleyici de 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();
- Panodaki birincil klibi ve içeriğini URI olarak alma:
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)
işlevini çağırarak URI'nin içerik URI'si olup olmadığını test edin. Bu yöntem,Uri
geçerli bir içerik sağlayıcıyı işaret etmiyorsa 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. Bu durumda, verileri almak için
ContentResolver.query()
numaralı telefonu arayın. Döndürülen değerCursor
.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ırma
Bir niyet yapıştırmak için önce genel pano alın. ClipData.Item
nesnesinin Intent
içerip içermediğini inceleyin. Ardından, getIntent()
işlevini çağırarak amacı kendi depolama alanınıza kopyalayın. Aşağıdaki snippet bu durumu 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()
işlevini çağırdığında sistem genellikle bir kısa mesaj gösterir.
İletinin içindeki metin aşağıdaki biçimi içeriyor:
APP pasted from your clipboard
Uygulamanız aşağıdakilerden birini yaptığında sistemde kısa mesaj gösterilmez:
- Kendi uygulamanızdan
ClipData
erişir. - Belirli bir uygulamadan
ClipData
öğesine tekrar tekrar erişildiğinde. Toast yalnızca uygulamanız ilk kez söz konusu uygulamadaki verilere eriştiğinde gösterilir. getPrimaryClip()
yerinegetPrimaryClipDescription()
çağrısı yaparak klip nesnesinin meta verilerini alır.
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. Daha sonra yapıştırma uygulamaları bu URI'yi panodan alır ve veritabanı verilerini veya dosya akışı tanımlayıcılarını almak için kullanır.
Yapıştırma uygulamasında yalnızca verilerinizin içerik URI'si bulunduğundan hangi veri parçasının alınması gerektiğini bilmesi gerekir. Bu bilgileri, URI'nin kendisinde veriler için bir tanımlayıcıyı kodlayarak veya kopyalamak istediğiniz verileri döndüren benzersiz bir URI sağlayarak iletebilirsiniz. Hangi tekniği seçeceğiniz, verilerinizin düzenine bağlıdır.
Aşağıdaki bölümlerde URI'lerin nasıl ayarlanacağı, 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 ilkelerini bildiğiniz varsayılır.
URI'deki bir tanımlayıcıyı kodlama
Verileri URI ile birlikte panoya kopyalamak için kullanışlı bir teknik, URI'deki veriler için bir tanımlayıcıyı kodlamaktır. İçerik sağlayıcınız daha sonra tanımlayıcıyı URI'den alabilir ve verileri almak için kullanabilir. Yapıştırma uygulamasının, tanımlayıcının var olduğunu bilmesi gerekmez. Bu işlevin tek yapması gereken, URI ve tanımlayıcıdan oluşan "referansınızı" panodan almak, içerik sağlayıcınıza vermek ve verileri geri almaktır.
Genellikle bir tanımlayıcıyı URI'nin sonuna ekleyerek içerik URI'sine kodlarsınız. Örneğin, sağlayıcı URI'nizi aşağıdaki dize olarak tanımladığınızı varsayalım:
"content://com.example.contacts"
Bu URI'ye bir ad kodlamak istiyorsanız aşağıdaki 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'nin kopyalama için olduğunu belirten yeni bir URI yolu eklemek isteyebilirsiniz. Örneğin, aşağıdaki URI yollarınızın olduğunu 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ştirme yoluyla "kopyalama" URI'sini algılayabilir ve kopyalama ile yapıştırmaya özel kodla işleyebilirsiniz.
Verilerinizi düzenlemek için zaten bir içerik sağlayıcı, dahili veritabanı veya dahili tablo kullanıyorsanız genellikle kodlama tekniğini kullanırsınız. Bu durumlarda, kopyalamak istediğiniz birden fazla veri parçası ve muhtemelen her parça için benzersiz bir tanımlayıcı vardır. Yapıştırma uygulamasından gelen bir sorguya yanıt olarak, verileri tanımlayıcılarına göre arayabilir ve döndürebilirsiniz.
Birden fazla veri parçanız yoksa tanımlayıcı kodlamanız gerekmez. Sağlayıcınıza özgü bir URI kullanabilirsiniz. Sağlayıcınız, bir sorguya yanıt olarak o anda içerdiği verileri döndürür.
Veri yapılarını kopyalama
Karmaşık verileri kopyalayıp yapıştırmak için ContentProvider
bileşeninin alt sınıfı olarak bir içerik sağlayıcı ayarlayın. Panoya koyduğunuz URI'yi, sağlamak istediğiniz kayda yönlendirecek şekilde kodlayın. Ayrıca, uygulamanızın mevcut durumunu da göz önünde bulundurun:
- İçerik sağlayıcınız varsa işlevselliğini artırabilirsiniz. Verileri yapıştırmak isteyen uygulamalardan gelen URI'leri işlemek için yalnızca
query()
yöntemini değiştirmeniz gerekebilir. Büyük ihtimalle yöntemi, "kopyalama" URI kalıbını işleyecek şekilde değiştirmek isteyeceksiniz. - Uygulamanız dahili bir veritabanı kullanıyorsa bu veritabanını, kopyalama işlemini kolaylaştırmak için bir içerik sağlayıcıya taşıyabilirsiniz.
- Veritabanı kullanmıyorsanız tek amacı panodan yapıştırılan 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ırma uygulamaları, bu yöntemi panoya koyduğunuz URI ile kullanarak verilerinizi alabileceklerini varsayar. Kopyalama işlemini desteklemek için bu yöntemin, özel bir "copy" yolu içeren URI'leri algılamasını sağlayın. Uygulamanız daha sonra panoya yerleştirilecek bir "kopyalama" URI'si oluşturabilir. Bu URI, kopyalama yolunu ve kopyalamak istediğiniz kayda yönelik bir işaretçiyi içerir.
-
getType()
- Bu yöntem, kopyalamayı planladığınız verilerin MIME türlerini döndürmelidir. MIME türlerini yeni
ClipData
nesnesine yerleştirmek içinnewUri()
yöntemgetType()
çağrıları.Karmaşık verilerin MIME türleri İçerik sağlayıcılar bölümünde açıklanmıştır.
insert()
veya update()
gibi diğer içerik sağlayıcı yöntemlerine sahip olmanız gerekmez.
Yapıştırma uygulamalarının yalnızca desteklenen MIME türlerinizi alması ve sağlayıcınızdan veri kopyalaması gerekir.
Bu yöntemler zaten varsa kopyalama işlemlerine müdahale etmez.
Aşağıdaki snippet'lerde, uygulamanızı karmaşık verileri kopyalayacak şekilde nasıl ayarlayacağınız gösterilmektedir:
-
Uygulamanızın genel sabitlerinde, temel bir URI dizesi ve veri 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 verileri kopyaladığı etkinlikte, verileri panoya kopyalayacak 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 küresel kapsamında bir URI eşleştirici oluşturun ve panoya koyduğunuz 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, nasıl kodladığınıza bağlı olarak farklı URI kalıplarını işleyebilir ancak yalnızca pano kopyalama işlemi için olan kalıp 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ürmek üzere
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'si alıp veri almak ve yapıştırmak için nasıl kullanacağınız açıklanmaktadır.
Veri akışlarını kopyalama
Büyük miktarda metin ve ikili veriyi akış olarak kopyalayıp yapıştırabilirsiniz. Veriler aşağıdaki gibi biçimlerde olabilir:
- Gerçek cihazda depolanan dosyalar
- Soketlerden gelen 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ı nesnesiyle erişim sağlar. Yapıştırma uygulaması, bu dosya tanımlayıcısını kullanarak veri akışını okur.
Uygulamanızı bir sağlayıcıyla veri akışı kopyalayacak şekilde ayarlamak için aşağıdaki adımları uygulayın:
-
Panoya koyduğunuz veri akışı için bir içerik URI'si ayarlayın. Bunu yapma seçenekleri şunlardır:
- URI'ye tanımlayıcı kodlama bölümünde açıklandığı gibi, veri akışı için bir tanımlayıcıyı URI'ye kodlayın ve ardından sağlayıcınızda tanımlayıcıları ve ilgili akış adını içeren bir tablo tutun.
- Akış adını doğrudan URI'ye kodlayın.
- Sağlayıcıdan her zaman mevcut yayını döndüren benzersiz bir URI kullanın. Bu seçeneği kullanırsanız URI'yi 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ırma uygulamaları, panodaki verileri yapıştırıp yapıştıramayacaklarını belirlemek için bu bilgilere ihtiyaç duyar.
- Bir akış için dosya tanımlayıcısı döndüren
ContentProvider
yöntemlerinden birini uygulayın. İçerik URI'sindeki tanımlayıcıları kodlarsanı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 panodan klibi alır, URI'yi alır ve akışı açan bir ContentResolver
dosya tanımlayıcı yöntemine yapılan çağrıda kullanır. ContentResolver
yöntemi, ilgili ContentProvider
yöntemini çağırarak içerik URI'sini iletir. Sağlayıcınız, dosya tanımlayıcıyı ContentResolver
yöntemine döndürür. Daha sonra, yapıştırma uygulamasının akıştaki verileri okuması gerekir.
Aşağıdaki listede, içerik sağlayıcı için en önemli dosya tanımlayıcı yöntemleri gösterilmektedir. Bunların her birinin, yöntem adına "Descriptor" dizesi eklenmiş ilgili bir ContentResolver
yöntemi vardır. Örneğin, ContentResolver
analogunun
openAssetFile()
karşılığı
openAssetFileDescriptor()
'dir.
-
openTypedAssetFile()
-
Bu yöntem, yalnızca sağlanan MIME türü sağlayıcı tarafından destekleniyorsa bir öğe dosyası tanımlayıcısı döndürür. Yapıştırma işlemini yapan uygulama olan arayan, bir MIME türü kalıbı sağlar. Bir URI'yi panoya kopyalayan uygulamanın içerik sağlayıcısı, bu MIME türünü sağlayabiliyorsa
AssetFileDescriptor
dosya tutucusu döndürür, sağlayamıyorsa 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 kullanabilirsiniz.
-
openAssetFile()
-
Bu yöntem,
openTypedAssetFile()
'nin daha genel bir biçimidir. İzin verilen MIME türleri için filtreleme yapmaz ancak dosyaların alt bölümlerini okuyabilir. -
openFile()
-
Bu,
openAssetFile()
öğesinin daha genel bir biçimidir. Dosyaların alt bölümlerini okuyamaz.
İsteğe bağlı olarak dosya tanımlayıcı yönteminizle birlikte
openPipeHelper()
yöntemini kullanabilirsiniz. Bu, yapıştırma uygulamasının, bir kanal kullanarak akış verilerini arka plan iş parçacığında okumasına olanak tanır. Bu yöntemi kullanmak için ContentProvider.PipeDataWriter
arayüzünü uygulayın.
Etkili kopyalama ve yapıştırma işlevleri tasarlama
Uygulamanız için etkili bir kopyalama ve yapıştırma işlevi tasarlarken şu noktaları göz önünde bulundurun:
- Pano'da her zaman yalnızca bir klip bulunur. Sistemdeki herhangi bir uygulama tarafından yapılan yeni bir kopyalama işlemi, önceki klibin üzerine yazar. Kullanıcı, uygulamanızdan ayrılıp geri dönmeden önce kopyalama işlemi yapabileceğinden, panoda daha önce uygulamanızda kopyalanan öğenin bulunduğunu varsayamazsınız.
-
Klip başına birden fazla
ClipData.Item
nesnenin 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
nesnelerin aynı biçimde olmasını istersiniz. Yani, tümü basit metin, içerik URI'si veyaIntent
olmalı ve karıştırılmamalıdır. -
Veri sağladığınızda farklı MIME temsilleri sunabilirsiniz. Desteklediğiniz MIME türlerini
ClipDescription
öğesine ekleyin ve ardından MIME türlerini içerik sağlayıcınızda uygulayın. -
Pano'dan veri aldığınızda, uygulamanız kullanılabilir MIME türlerini kontrol etmekten ve ardından hangisini kullanacağına (varsa) karar vermekten sorumludur. Pano üzerinde bir klip olsa ve kullanıcı yapıştırma isteğinde bulunsa bile uygulamanızın yapıştırma işlemini yapması gerekmez. MIME türü uyumluysa yapıştırma işlemini gerçekleştirin. Panodaki verileri
coerceToText()
kullanarak metne dönüştürebilirsiniz. Uygulamanız, kullanılabilir MIME türlerinden birden fazlasını destekliyorsa kullanıcının hangisini kullanacağını seçmesine izin verebilirsiniz.