Kopyala ve yapıştır

Android, kopyalama ve yapıştırma işlemi için pano tabanlı güçlü bir çerçeve sunar. Basit kampanyaları destekler ve karmaşık veri türlerini (metin dizeleri, karmaşık veri yapıları, metin ve ikili akış dahil) veriler ve uygulama öğeleri. Basit metin verileri doğrudan panoda saklanırken karmaşık verileri, yapıştırma uygulamasının bir içerik sağlayıcıyla çözdüğü bir referans olarak saklanır. Kopyalanıyor hem bir uygulama içinde hem de bahsedeceğim.

Çerçevenin bir kısmında içerik sağlayıcılar kullanıldığı için bu belgede Android Content Provider API'si İçerik sağlayıcılar.

Kullanıcılar, içeriği panoya kopyalarken geri bildirim bekler. Bu nedenle, kopyalama ve yapıştırma özelliğini etkinleştirir. Android, Android 13'te (API düzeyi 33) kopyalama yaparken kullanıcılara varsayılan bir kullanıcı arayüzü gösterir. ve daha yüksek olabilir. Bu özellik nedeniyle yinelenen bildirim riski vardır. Web sitemiz g.co/newsinitiative/labs üzerinden bu uç örnekte, Yinelenen bildirimlerden kaçınma bölümüne ekleyin.

Android 13 pano bildirimini gösteren animasyon
Şekil 1. Android'de içerik panoya girdiğinde gösterilen kullanıcı arayüzü 13 ve üzeri.

Android 12L (API düzeyi 32) ve önceki sürümlerde kopyalama yaparken kullanıcılara manuel olarak geri bildirim sağlayın. Görüntüleyin bununla ilgili öneriler bulabilirsiniz.

Pano çerçevesi

Pano çerçevesini kullanırken verileri bir klip nesnesine yerleştirin, ardından klip nesnesini yerleştirin. panodan takip edin. Klip nesnesi şu üç biçimden birinde olabilir:

Metin
. Metin dizesi. Dizeyi doğrudan klip nesnesinin içine yerleştirin. Daha sonra panoya ekleyebilirsiniz. Dizeyi yapıştırmak için panodan klip nesnesini alın ve dizeyi uygulamanızın depolama alanına yapıştırın.
URI
. Herhangi birini temsil eden Uri nesnesi bir yolunu sunar. Bu, esas olarak bir içerik sağlayıcıdan karmaşık verilerin kopyalanması içindir. Kopyalamak için bir Uri nesnesini klip nesnesine yerleştirin ve klip nesnesini panoya ekleyebilirsiniz. Verileri yapıştırmak için klip nesnesini, Uri nesnesini ve bir veri kaynağına (örneğin bir içerik sağlayıcıya) çözümlemeli ve uygulamanızın depolama alanına yapıştırın.
Amaç
. Intent. Bu uygulama kısayollarının kopyalanmasını destekler. Verileri kopyalamak için bir Intent oluşturun, klip nesnesine koyabilir ve klip nesnesini panoya koyabilirsiniz. Verileri yapıştırmak için klip nesnesini kopyalayın ve ardından Intent nesnesini uygulamanıza kopyalayın. görünür.

Panoda aynı anda yalnızca bir klip nesnesi bulunur. Bir uygulama, önceki klip nesnesi kaybolur.

Kullanıcıların uygulamanıza veri yapıştırmasına izin vermek istiyorsanız tüm uygulama türlerini işlemeniz gerekmez. dışı verilerdir. Kullanıcılara yapıştırma seçeneği sunmadan önce panodaki verileri inceleyebilirsiniz. Klip nesnesi, belirli bir veri formunun yanı sıra hangi MIME türünü belirten meta veriler de içerir? farklı türler vardır. Bu meta veriler, uygulamanızın faydalı bir şeyler yapıp yapamayacağına karar vermenize yardımcı olur pano verileriyle birlikte. Örneğin, ağırlıklı olarak metinlerle ilgili işlem yapan bir uygulamanız varsa URI veya intent içeren klip nesnelerini yoksaymak isteyebilirsiniz.

Kullanıcıların panodaki veri biçiminden bağımsız olarak metin yapıştırmasına da izin vermek isteyebilirsiniz. Alıcı: bunu yapın, pano verilerini metin biçiminde göstermeye zorlayın ve ardından bu metni yapıştırın. Bu Panoyu metne dönüştürme bölümünde bulabilirsiniz.

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, global ClipboardManager sınıf. Bu sınıfı doğrudan örneklendirmeyin. Bunun yerine, getSystemService(CLIPBOARD_SERVICE)

ClipData, ClipData.Item ve ClipDescription

Panoya veri eklemek için bir Şunları içeren ClipData nesne verilerin bir açıklamasıdır. Panoda her defasında başka bir ClipData tutulup gerekir. ClipData, bir ClipDescription nesne ve bir veya daha fazla ClipData.Item nesne.

Bir ClipDescription nesnesi, kliple ilgili meta verileri içerir. Özellikle, klibin verileri için bir dizi kullanılabilir MIME türü içerir. Ayrıca Android 12 (API düzeyi 31) ve sonraki sürümlerde meta veriler, nesnenin içerir stilize edilmiş metin ve kullanıcıların nesnedeki metnin türünü. Panoya bir klip yerleştirdiğinizde bu bilgiler, uygulamaları yapıştırırken kullanılabilir ve klip verilerini işleyip işleyemediklerini inceleyebilir.

ClipData.Item nesnesi metin, URI veya intent verilerini içerir:

Metin
. CharSequence.
URI
. Uri. Bu genellikle bir içerik sağlayıcı URI'si içerir, ancak herhangi bir URI izin verilir. Verileri sağlayan uygulama, URI'yı panoya yerleştirir. Uygulamalar verileri yapıştırmak isteyenlerin URI'yı panodan alıp içeriğe erişmek için kullanması veya başka bir veri kaynağında bulunabilir ve verileri alabilir.
Amaç
. Intent. Bu veri türü, bir uygulama kısayolunu panoya ekleyebilirsiniz. Kullanıcılar, bu kısayolu daha sonra kullanmak üzere uygulamalarına yapıştırabilir.

Bir klibe birden fazla ClipData.Item nesnesi ekleyebilirsiniz. Bu sayede kullanıcılar birden fazla seçimi tek bir klip olarak yapıştırabilirsiniz. Örneğin, kullanıcı aynı anda birden çok öğe seçerse, tüm öğeleri tek seferde panoya kopyalayabilirsiniz. Yapılacaklar her liste öğesi için ayrı bir ClipData.Item oluşturun ve daha sonra ClipData nesnesine ClipData.Item nesne eklendi.

ClipData kolaylık yöntemleri

ClipData sınıfı, Tek bir ClipData.Item nesnesi ve basit bir öğe içeren ClipData nesnesi ClipDescription nesne:

newPlainText(label, text)
Tek ClipData.Item nesnesi bulunan ClipData nesnesini döndürür bir metin dizesi içeriyorsa. ClipDescription nesnesinin etiketi label. ClipDescription alanındaki tek MIME türü: MIMETYPE_TEXT_PLAIN.

Bir metin dizesinden klip oluşturmak için newPlainText() öğesini kullanın.

newUri(resolver, label, URI)
Tek ClipData.Item nesnesi bulunan ClipData nesnesini döndürür URI içerir. ClipDescription nesnesinin etiketi label. URI bir içerik URI'si ise (yani, Uri.getScheme(). content: değerini döndürür; yöntem ContentResolver resolver kullanılarak sağlanan nesne içerik sağlayıcı. Daha sonra bunları ClipDescription konumunda depolar. Benzersiz bir URI için bir content: URI ise, yöntem MIME türünü MIMETYPE_TEXT_URILIST.

URI'dan klip oluşturmak için newUri() kullanın. Bu, özellikle de content: URI.

newIntent(label, intent)
Tek ClipData.Item nesnesi bulunan ClipData nesnesini döndürür bir Intent içerir. ClipDescription nesnesinin etiketi label. MIME türü şuna ayarlanır: MIMETYPE_TEXT_INTENT

Intent nesnesinden klip oluşturmak için newIntent() işlemini kullanın.

Pano verilerini metne dönüştürme

Uygulamanız yalnızca metin işlese bile aşağıdakileri kullanarak metin dışı verileri panodan kopyalayabilirsiniz: dönüşüm için ClipData.Item.coerceToText(). yöntemidir.

Bu yöntem, ClipData.Item içindeki verileri metne dönüştürür ve bir CharSequence. ClipData.Item.coerceToText() işlevinin döndürdüğü değer temel alınmıştır. ClipData.Item içindeki veri biçiminde:

Metin
. ClipData.Item metin ise (yani getText() null değildir; coerceToText(), metni döndürür.
URI
. ClipData.Item bir URI ise (yani getUri() boş değildir: coerceToText(), bunu içerik URI'si olarak kullanmaya çalışır.
  • URI bir içerik URI'siyse ve sağlayıcı bir metin akışı döndürebiliyorsa coerceToText() bir metin akışı döndürür.
  • URI bir içerik URI'siyse ancak sağlayıcı bir metin akışı sunmuyorsa coerceToText(), URI'nın bir gösterimini döndürür. Bu temsil tarafından döndürülen Uri.toString()
  • URI bir içerik URI'si değilse coerceToText() bunun bir temsilini döndürür URI'yı ekleyin. Temsil, Uri.toString()
Amaç
ClipData.Item bir Intent ise (yani getIntent() null değildir - coerceToText(), bunu bir Intent URI'sine dönüştürür ve döndürür. Temsil, Intent.toUri(URI_INTENT_SCHEME)

Pano çerçevesi Şekil 2'de özetlenmiştir. Bir uygulama, verileri kopyalamak için ClipboardManager genel panosunda ClipData nesnesi var. İlgili içeriği oluşturmak için kullanılan ClipData, bir veya daha fazla ClipData.Item nesne ve bir tane içeriyor ClipDescription nesne. Bir uygulama, verileri yapıştırmak için ClipData alır. MIME türünü ClipDescription kaynağından alır ve verileri şuradan alır: ClipData.Item veya atıfta bulunulan içerik sağlayıcıdan ClipData.Item.

Kopyalama ve yapıştırma çerçevesinin blok diyagramını gösteren resim
Şekil 2. Android pano çerçevesi.

Panoya kopyala

Verileri panoya kopyalamak için global ClipboardManager nesnesini herkese açık kullanıcı adı olarak kullanın. ClipData nesnesi oluşturun, ClipDescription ve bir veya daha fazlasını ekleyin ClipData.Item nesne var. Sonra, tamamlanmış ClipData nesnesini ClipboardManager nesne algılandı. Bu, aşağıdaki prosedürde daha ayrıntılı bir şekilde açıklanmaktadır:

  1. Verileri içerik URI'si kullanarak kopyalıyorsanız bir içerik sağlayıcı ayarlayın.
  2. 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);
    
  3. 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!");
      
    • Bir URI için

      Bu snippet içerik URI'sine kayıt kimliğini kodlayarak bir URI oluşturur. sağlayıcıdır. Bu teknik, bkz. URI'da bir tanımlayıcıyı kodlama bölümünde.

      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);
      
    • Amaç için

      Bu snippet, bir uygulama için bir Intent oluşturur ve ardından bunu klip nesnesine ekleyin:

      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);
      
  4. 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 ver

Kullanıcılar, bir uygulama panoya içerik kopyaladığında görsel geri bildirim bekler. Bu işlem tamamlandı Android 13 ve sonraki sürümlerdeki kullanıcılar için otomatik olarak oluşturulur, ancak öncesinde manuel olarak uygulanması gerekir sürümleri vardır.

Android 13'ten itibaren içerik eklendiğinde sistem standart bir görsel onay mesajı gösterir. panoya gönderir. Yeni onay şunları yapar:

  • İçeriğin başarıyla kopyalandığını onaylar.
  • Kopyalanan içeriğin önizlemesini sunar.

Android 13 pano bildirimini gösteren animasyon
Şekil 3. Android'de içerik panoya girdiğinde gösterilen kullanıcı arayüzü 13 ve üzeri.

Android 12L (API düzeyi 32) ve önceki sürümlerde kullanıcılar başarıyla kopyalanıp kopyalanmadığından emin olmayabilir. geri bildirimde bulunurlar. Bu özellik, kullanıcılara pano üzerinde daha fazla kontrol olanağı sağlar.

Yinelenen bildirimlerden kaçının

Android 12L (API düzeyi 32) ve önceki sürümlerde, kopyalama işlemi başarılı olduğunda kullanıcıları uyarmanızı öneririz. Toast gibi bir widget kullanarak görsel ve uygulama içi geri bildirim göndererek Snackbar olarak gönderin.

Bilgilerin yinelenen şekilde gösterilmesini önlemek için kısa mesajları kaldırmanızı önemle tavsiye ederiz veya atıştırmalık çubuklarının yer aldığı reklamlar, uygulama içi kopyadan sonra gösteriliyor.

Uygulama içi kopyadan sonra yayın atıştırmalık çubuğu.
Şekil 4. Android 13'te kopyalama onayı atıştırmalık çubuğunu gösterirseniz Kullanıcı yinelenen iletilerle karşılaşır.
ziyaret edin.
'nı inceleyin.
Uygulama içi kopyadan sonra kısa mesaj yayınlayın.
5. Şekil. Android 13'te kopyalama onayı kısa mesajı gösteriyorsanız Kullanıcı yinelenen iletilerle karşılaşır.

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 şifre veya kredi kartı gibi hassas içerikleri panoya kopyalamasına izin veriyorsa kart bilgileri, ClipData uygulamasında ClipDescription uygulamasına bir bayrak eklemeniz gerekiyor ClipboardManager.setPrimaryClip() numaralı telefonu aramadan önce. Bu işaretin eklenmesi, hassasiyeti içeriğin Android 13 ve sonraki sürümlerde kopyalanan içeriğin görsel onayında görünmesini engeller.

Hassas içeriği işaretlemeden metin önizlemesi kopyalandı
Şekil 6. Metin önizlemesi, hassas içerik işareti olmadan kopyalandı.
ziyaret edin.
'nı inceleyin.
Hassas içeriği işaretleyen metin önizlemesi kopyalandı.
7. Şekil. Hassas içerik işaretiyle metin önizlemesi kopyalandı.

Hassas içeriği işaretlemek için ClipDescription öğesine fazladan bir boole ekleyin. Tüm uygulamalar şunları yapmalıdır: (hedeflenen API düzeyinden bağımsız olarak).

// 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, global pano nesnesini alarak verileri panodan yapıştırın, klip nesnesini alma, verilerine bakma ve mümkünse verileri klip nesnesinden kopyalama . Bu bölümde, üç pano biçiminin nasıl yapıştırılacağı ayrıntılı olarak açıklanmaktadır dışı verilerdir.

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. Sonra klip nesnesini oluşturun ve metni getText() kullanarak aşağıdaki şekilde kendi depolama alanınıza kopyalayın: şu prosedürü uygulayın:

  1. Şunu kullanarak global ClipboardManager nesnesini alın: getSystemService(CLIPBOARD_SERVICE). Ayrıca, şunu içerecek bir genel değişken bildirin: yapıştırılan metin:

    Kotlin

    var clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    var pasteData: String = ""
    

    Java

    ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
    String pasteData = "";
    
  2. "Yapıştır" işlemini etkinleştirmenin veya devre dışı bırakmanın gerekip gerekmediğini belirleme seçeneğinin yanındaki etkinliği'ne dokunun. Panonun klip içerdiğini ve veri türünü işleyebildiğinizi doğrulayın kliple temsil edilir:

    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);
    }
    
  3. Panodaki verileri kopyalayın. Koddaki bu noktaya yalnızca "Yapıştır" menü öğesi etkinleştirildiğinde, panonun düz metin içerdiğini varsayabilirsiniz metin. Bir metin dizesi mi yoksa düz metne işaret eden bir URI mi içerdiğini bilmiyorsunuz. Aşağıdaki kod snippet'i bunu test eder, ancak yalnızca düz metni işlemeye yönelik kodu 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 şunu yapıldığını belirlerseniz: MIME türlerinden birini işleyip ContentResolver oluşturup uygun içeriği çağırın sağlayıcı yöntemini kullanın.

Aşağıdaki prosedürde, içerik URI'sine dayalı olarak içerik sağlayıcıdan nasıl veri alınacağı açıklanmaktadır. tıklayın. Uygulamanın kullanabileceği bir MIME türünün sağlar.

  1. Bir 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";
    
  2. Genel panoyu alın. İçeriğe erişebilmek için içerik çözümleyici de edinin sağlayıcı:

    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();
    
  3. Birincil klibi panodan 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();
    
  4. URI'nın bir içerik URI'si olup olmadığını test etmek için şunu çağırarak: getType(Uri) 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);
    
  5. İçerik sağlayıcının, uygulamanın anladığı bir MIME türünü destekleyip desteklemediğini test edin. Eğer çağırın, ContentResolver.query(). bu verileri almak için iyi bir fırsattır. Döndürülen değer: 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();
                 }
             }
         }
    }
    

Niyet Yapıştır

Niyeti yapıştırmak için önce genel panoyu alın. ClipData.Item nesnesini inceleyin bir Intent içerip içermediğini kontrol edin. Ardından şunu kopyalamak için getIntent() işlevini çağırın: depolama alanına sahip olursunuz. Aşağıdaki snippet bunu göstermektedir:

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 sistem, uygulamanız gerektiğinde genellikle bir posta mesajı gösterir. telefon aramaları getPrimaryClip(). İletinin içindeki metin aşağıdaki biçimdedir:

APP pasted from your clipboard

Uygulamanız aşağıdakilerden birini yaptığında sistem bir durum mesajı mesajı göstermez:

  • Erişimler Kendi uygulamanızdan ClipData.
  • Belirli bir uygulamadan ClipData cihazına sürekli olarak erişir. Kısa mesaj yalnızca Uygulamanız o uygulamadaki verilere ilk kez eriştiğinde
  • Klip nesnesinin meta verilerini alır (örneğin, şunu çağırarak) getPrimaryClipDescription() (getPrimaryClip() yerine)

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. Kopyalamak için verileri görüntülemek için panoya bir içerik URI'si yerleştirin. Uygulamaları yapıştırdıktan sonra, bu URI'yı şuradan alın: panoya kaydedebilir ve veritabanı verilerini veya dosya akışı tanımlayıcılarını almak için kullanabilirsiniz.

Yapıştırma uygulaması yalnızca verilerinize ait içerik URI'sine sahip olduğundan, uygulamanızın hangi küçük bir dosyadır. Veriler için bir tanımlayıcı kodlayarak bu bilgileri sağlayabilirsiniz tıklayabilir veya kopyalamak istediğiniz verileri döndüren benzersiz bir URI sağlayabilirsiniz. Hangi verilerinizin nasıl düzenlendiğine bağlıdır.

Aşağıdaki bölümlerde, URI'ların nasıl ayarlanacağı, karmaşık verilerin nasıl sağlanacağı ve nasıl dosya sağlanacağı açıklanmaktadır. akışlar. Açıklamalarda içerik sağlayıcının genel ilkelerine aşina olduğunuz varsayılır tasarım.

URI'da bir tanımlayıcıyı kodlama

URI içeren bir panoya veri kopyalamak için yararlı bir teknik, URI'nın kendisindeki veriler. Daha sonra içerik sağlayıcınız, tanımlayıcıyı URI'dan alıp verileri almak için kullanır. Yapıştırma uygulamasının tanımlayıcının mevcut olduğunu bilmesi gerekmez. Google tek yapmanız gereken içerik sağlayıcınıza vermeniz ve verileri geri almanız gerekir.

Genellikle bir tanımlayıcıyı URI'nın sonunda birleştirerek bir içerik URI'si üzerinde 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, kopyalama içindir. Ö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"

Böylece bir "kopya" algılayabilir. Kalıp eşleştirmeye göre URI ve bunu özellikle kopyalama ve yapıştırma işlemlerine özeldir.

Halihazırda dahili bir içerik sağlayıcı kullanıyorsanız, normalde kodlama tekniğini kullanırsınız. verilerinizi düzenlemek için kullanabileceğiniz dahili bir tablodur. Böyle durumlarda, elinizde birden fazla ve muhtemelen her parça için benzersiz bir tanımlayıcı eklemeniz gerekir. bir uygulamayı yapıştırdığınızda, verileri tanımlayıcısına göre arayıp döndürebilirsiniz.

Birden çok veriniz yoksa muhtemelen bir tanımlayıcıyı kodlamanız gerekmez. Sağlayıcınıza özgü bir URI kullanabilirsiniz. Sağlayıcınız, bir sorguya yanıt olarak verilerini de içerebilir.

Veri yapılarını kopyalama

Karmaşık verileri ContentProvider. bir bileşenidir. Panoya yerleştirdiğiniz URI'yı, tam olarak eklemek istediğiniz kaydı işaret edecek şekilde kodlayın sağlar. Ayrıca, uygulamanızın mevcut durumunu da göz önünde bulundurun:

  • Halihazırda bir içerik sağlayıcınız varsa işlevselliğini ekleyebilirsiniz. Yalnızca query() yöntemini, bu API'yi kullanan uygulamalardan gelen URI'leri işleyecek şekilde değiştirmesi verileri yapıştırmak istiyorsanız. Muhtemelen yöntemi bir "kopya" işlemini işleyecek şekilde değiştirmek isteyebilirsiniz. URI desen.
  • Uygulamanızda dahili bir veritabanı kullanılıyorsa bu veritabanını taşımak isteyebilirsiniz. kopyalamayı kolaylaştırmak için bir içerik sağlayıcıya.
  • Veritabanı kullanmıyorsanız tek amacı, panodan yapıştırma işlemi yapan uygulamalara veri sunmaktır.

İçerik sağlayıcıda, aşağıdaki yöntemlerin en az birini geçersiz kılın:

query()
Uygulamalar yapıştırılırken, bu yöntemi istediğiniz URI ile kullanarak verilerinizi alabilecekleri varsayılır panoya koyabilirim. Kopyalamayı desteklemek için bu yöntemin, özel bir "kopyala" yol'a dokunun. Ardından, uygulamanız bir "kopya" oluşturabilir bir pano da mevcuttur.
getType()
Bu yöntem, kopyalamak istediğiniz verilerin MIME türlerini döndürmelidir. Yöntem newUri(). MIME türlerini yeni ClipData içine yerleştirmek için getType() çağrısı nesnesini tanımlayın.

Karmaşık verilere ilişkin MIME türleri şurada açıklanmıştır: İçerik sağlayıcılar.

Örneğin, insert(). veya update(). Yapıştırma uygulamasının yalnızca desteklenen MIME türlerinizi alması ve sağlayıcınızdan veri kopyalaması gerekir. Bu yöntemleri zaten kullanıyorsanız kopyalama işlemlerini engellemezler.

Aşağıdaki snippet'ler, uygulamanızı karmaşık verileri kopyalayacak şekilde nasıl ayarlayacağınızı gösterir:

  1. Uygulamanızın genel sabit değerlerinde, bir taban URI dizesi ve verileri kopyalamak için kullandığınız URI dizelerini tanımlar. Kopyalanan dosya için de bir MIME türü bildir dışı verilerdir.

    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";
    
  2. Kullanıcıların veri kopyaladığı etkinlikte, verileri panoya kopyalayacak kodu ayarlayın. Kopyalama isteğine yanıt olarak URI'yı 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);
    
  3. İçerik sağlayıcınızın global kapsamında bir URI eşleştirici oluşturun ve şunu içeren bir URI kalıbı ekleyin: panoya yerleştirdiğiniz URI'lerle eşleşir.

    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);
    
  4. Ayarlayın: query(). yöntemidir. Bu yöntem, onu nasıl kodladığınıza bağlı olarak farklı URI kalıplarını işleyebilir, ancak yalnızca panoya kopyalama işleminin kalıbı gösterilmektedir.

    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.
        ...
    }
    
  5. getType() yöntemini, kopyalanan öğe için uygun bir MIME türü döndürecek şekilde ayarlayın veri:

    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, içerik URI'sini bulun ve verileri alıp yapıştırmak için kullanın.

Veri akışlarını kopyala

Büyük miktarda metin ve ikili veriyi akış olarak kopyalayıp yapıştırabilirsiniz. Verilerde formlar olabilir Örneğin:

  • Asıl cihazda depolanan dosyalar
  • Yuvalardan akışlar
  • Bir sağlayıcının temel veritabanı sisteminde depolanan büyük miktarlarda veri

Veri akışları için içerik sağlayıcı, bir dosya tanımlayıcı nesnesiyle verilerine erişim sağlar. örneğin: AssetFileDescriptor, (Cursor nesnesi) oluşturun. Yapıştırma uygulaması, bu veri akışını kullanarak veri akışını okur. dosya tanımlayıcısıdır.

Uygulamanızı bir sağlayıcıyla veri akışını kopyalayacak şekilde ayarlamak için aşağıdaki adımları uygulayın:

  1. Panoya koyduğunuz veri akışı için bir içerik URI'si oluşturun. Seçenekler şunları içerir:
    • Veri akışı için bir tanımlayıcıyı aşağıdaki bölümünde açıklandığı gibi URI üzerine kodlayın: URI bölümünde bir tanımlayıcıyı kodlayın ve ardından içinde tanımlayıcılar ve ilgili akış adını içeren bir tablo görürsünüz.
    • 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. Şu durumda: Bu seçeneği kullanırsanız sağlayıcınızı farklı bir akışa yönlendirecek şekilde güncellemeyi unutmayın. .
  2. Sunmayı planladığınız her veri akışı türü için bir MIME türü sağlayın. Uygulamalar yapıştırılıyor ve verileri panoya yapıştırıp yapıştıramayacağını belirlemek için bu bilgilere ihtiyaç duyar.
  3. Şu öğe için dosya açıklayıcısı döndüren ContentProvider yöntemlerinden birini uygulayın: bir deneyimdir. Tanımlayıcıları içerik URI'sinde kodluyorsanız hangi akışı açın.
  4. Veri akışını panoya kopyalamak için içerik URI'sini oluşturun ve panoya yerleştirin. panoya ekleyebilirsiniz.

Uygulama, veri akışını yapıştırmak için klibi panodan alır, URI'yı alır ve daha sonra akışı açan bir ContentResolver dosyası açıklayıcı yöntemine çağrıda bulunur. İlgili içeriği oluşturmak için kullanılan ContentResolver yöntemi, karşılık gelen ContentProvider yöntemini çağırır. içerik URI'si iletmektir. Sağlayıcınız, dosya açıklayıcısını ContentResolver yöntemini çağırın. Ardından, yapıştırma uygulaması, bu verileri kullanabilirsiniz.

Aşağıdaki liste, bir içerik sağlayıcı için en önemli dosya tanımlayıcı yöntemlerini göstermektedir. Her biri Bunların arasından dizeyle karşılık gelen bir ContentResolver yöntemi vardır "Açıklayıcı" sonuna eklenir. Örneğin, ContentResolver analog openAssetFile() : openAssetFileDescriptor().

openTypedAssetFile()

Bu yöntem, yalnızca sağlanan MIME türü sağlayıcı tarafından destekleniyor olmasıdır. Arayan (yapıştırmayı yapan uygulama) MIME türü kalıbı. Bir URI'yı pano, aşağıdakileri sağlayabilirse bir AssetFileDescriptor dosya işleyicisi döndürür MIME türünü ifade eder ve bu mümkün değilse bir istisna atar.

Bu yöntem dosyaların alt bölümlerini işler. Bunu, içerik sağlayıcı panoya kopyalandı.

openAssetFile()
. Bu yöntem, openTypedAssetFile() yönteminin daha genel bir biçimidir. Filtreleme, izin verilen MIME türlerine izin verir ancak dosyaların alt bölümlerini okuyabilir.
openFile()
. Bu, openAssetFile()'ın daha genel bir biçimidir. Şunun alt bölümlerini okuyamaz: dosyası olarak da kaydedebilir.

İsterseniz openPipeHelper(). yöntemini dosya tanımlayıcı yönteminizle birlikte kullanabilirsiniz. Bu işlem, yapıştırma uygulamasının akış verilerini arka plan iş parçacığı kullanıyor. Bu yöntemi kullanmak için ContentProvider.PipeDataWriter. kullanır.

Etkili kopyalama ve yapıştırma işlevi tasarlayın

Uygulamanız için etkili kopyalama ve yapıştırma işlevi tasarlamak için şu noktaları unutmayın:

  • Panoda her zaman yalnızca bir klip bulunur. Herhangi bir önceki klibin üzerine yazılır. Kullanıcı, uygulamadan uzaklaştırıp geri dönmeden önce kopyalama işlemini kullanıcının daha önce uygulamanızda kopyaladığı klibi içerir.
  • Klip başına birden fazla ClipData.Item nesnesinin amaçlanan amacı şudur: farklı biçimler yerine birden çok seçimin kopyalanıp yapıştırılmasını desteklemez tek bir seçime referansta bulunur. Genellikle ClipData.Item içindeki tüm seçenekleri aynı biçime sahip olmasını sağlayın. Yani, tümü basit metin, içerik ve URI veya Intent ve karışık değil.
  • Veri sağlarken farklı MIME gösterimleri sunabilirsiniz. MIME türlerini ekleme ClipDescription için desteğiniz, ardından MIME türlerini içerik sağlayıcınızda görüntüleyebilirsiniz.
  • Panodan veri aldığınızda, uygulamanız gereken bilgileri kontrol etmekten belirlemek ve hangisinin kullanılacağına karar vermek için kullanılır. Bir bir klip olup olmadığını kontrol edin. Kullanıcı bir yapıştırma isteğinde bulunursa uygulamanız gerekmez. tıklayın. MIME türü uyumluysa yapıştırma işlemini gerçekleştirin. Verileri panoda coerceToText() kullanarak metin yazın. Uygulamanız birden çok MIME türü seçerseniz kullanıcının hangi MIME türünü kullanacağını seçmesine izin verebilirsiniz.