Intent 如果ClipData.Item 是一个 Intent getIntent() 不为 null则 coerceToText() 会 将其转换为 Intent URI 并返回 , 每个剪切有多个 ClipData.Item 对象的预期目的是支持复制和粘贴多个选择而不是一个选择的不同引用形式 , ClipDescription对象包含关于剪切的元数据,ClipDescription 中的单一 MIME 类型为 MIMETYPE_TEXT_PLAIN,如需复制数据应用需要将一个 ClipData 对象放到 ClipboardManager 全局剪贴板中, 剪贴板一次只保留一个 ClipData ,该表示形式与 Intent.toUri(URI_INTENT_SCHEME) 返回的表示形式相同。
URI , Clipboard contains an invalid data type ) ; return false ; } } 从内容 URI 中粘贴数据 如果 ClipData.Item 对象包含内容 URI并且您已确定自己可以处理它的某种 MIME 类型请创建一个 ContentResolver然后调用相应 Content Provider 方法以检索数据,对于不是 content: URI 的 URI此方法会将 MIME 类型设置为 MIMETYPE_TEXT_URILIST,它支持 复制应用快捷方式 ,ClipDescription对象的标签设置为 label,如果支持请调用 ContentResolver.query() 以获取数据,ClipDescription对象的标签设置为label。
but the clipboard does not contain either // text or a Uri. Report an error. Log . e ( TAG , 1000 ) ; 或者 public class StatisticActivityLifecycleCallback implements Application . ActivityLifecycleCallbacks { private boolean isNullData false ; // 是否拿到剪贴板数据 Override public void onActivityStarted ( final Activity activity ) { . . . . ClipboardManager clipboardManager ( ClipboardManager ) MSApplication . mContext . getSystemService ( Context . CLIPBOARD_SERVICE ) ; ClipData clipData clipboardManager . getPrimaryClip ( ) ; if ( clipData null ) { isNullData true ; // 这里获取剪贴板数据 } else { isNullData false ; } . . . . } Override public void onActivityResumed ( Activity activity ) { // 这里重新获取一次剪贴板数据 } } 参考文章 《Android 官方文档》 android 剪切板遇到的坑 android Q以上剪贴板的坑 Android10填坑适配指南实际经验代码拒绝翻译 , URI) 返回一个 ClipData 对象该对象的单个 ClipData.Item 对象包含一个 URI, 剪切板类 ClipboardManager 在 Android 系统中系统剪贴板由全局 ClipboardManager 类表示,只有在“粘贴”菜单项处于启用状态时才能在项目中执行到这一步因此您可以假设剪贴板包含纯文本,具体来说它包含剪切的数据的可用 MIME 类型数组, then the paste operation is done if ( pasteData ! null ) { return true ; // The clipboard does not contain text. If it contains a URI, 在android Q以上的手机上当 activity 页面失去焦点的时候是获取不到 剪贴板的数据的直接返回null ,ClipData 包含一个 ClipDescription 对象以及一个或多个 ClipData.Item 对象,本部分将介绍在应用粘贴数据时可能会出现的通知并且还会详细说明了如何粘贴三种形式的剪贴板数据,以下代码段对此进行了测试但它仅显示用于处理纯文本的代码 // Responds to the user selecting paste case R . id . menu_paste : // Examines the item on the clipboard. If getText() does not return null, appIntent ) ; 将新的剪贴对象放到剪贴板中 // Set the clipboards primary clip. clipboard . setPrimaryClip ( clip ) ; 从剪贴板粘贴 如前所述您可以通过以下方法从剪贴板中粘贴数据获取全局剪贴板对象获取剪贴对象查看其数据然后将数据从剪贴对象复制到您自己的存储空间如果可以,。
disable the paste menu item. // If it does contain data, 复制到剪贴板 如前所述如需将数据复制到剪贴板您需要获取全局 ClipboardManager 对象的句柄创建一个 ClipData 对象向其中添加一个 ClipDescription 和一个或多个 ClipData.Item 对象然后将已完成的 ClipData 对象添加到 ClipboardManager 对象, null ,检查 ClipData.Item 对象以了解它是否包含 Intent,如需粘贴字符串您需要从剪贴板获取剪贴对象然后将字符串复制到应用的存储空间,只有在您的应用首次访问该应用的数据时系统才会显示消息框, ClipData 便捷方法 ClipData 类提供静态便捷方法用于创建具有单个 ClipData.Item 对象和一个简单 ClipDescription 对象的 ClipData 对象 newPlainText(label, newUri(resolver, 在应用访问剪贴板数据时显示系统通知 在 Android 12API 级别 31及更高版本中系统通常会在应用调用 getPrimaryClip() 时显示消息框消息, URI 一个 Uri 对象 表示任何形式的 URI, Intent 一个 Intent 。
Android Q中只有当应用处于可交互情况默认输入法本身就可交互才能访问剪切板和监听剪切板变化在onResume回调也无法直接访问剪切板这么做的好处是避免了一些应用后台疯狂监听响应剪切板的内容疯狂弹窗,您应该在 MIME 类型兼容时执行粘贴操作, and its data is // the Uri previously created. ClipData clip ClipData . newUri ( getContentResolver ( ) , intent) 返回一个 ClipData对象该对象的单个ClipData.Item对象包含一个 Intent。
即使剪贴板中有剪切且用户请求粘贴您的应用也无需执行粘贴操作。
然后调用 getIntent()以将相应 Intent 复制到您自己的存储空间,将您支持的 MIME 类型添加到 ClipDescription然后在Content Provider中实现这些 MIME 类型,为此您可以将剪贴板数据强制转换为文本表示形式然后粘贴相应文本, 此方法可将ClipData.Item中的数据转换为文本并返回一个 CharSequence, 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 , 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 , newIntent(label,简单的文本数据直接存储在剪贴板中而复杂的数据则存储为引用执行粘贴操作的应用使用 Content Provider 对其进行解析,以下过程对此进行了详细介绍 如果您要使用内容 URI 复制数据请设置一个 Content Provider。
您目前还不知道它是否包含文本字符串或指向纯文本的 URI,如果该 URI 是内容 URIUri.getScheme() 返回 content:则此方法会使用 resolver 中提供的 ContentResolver对象从 Content Provider 检索可用的 MIME 类型并将其存储在 ClipDescription 中,您应验证剪贴板是否包含剪切以及您是否可以处理剪切所代表的数据类型 // Gets the ID of the paste menu item MenuItem pasteItem menu . findItem ( R . id . menu_paste ) ; // If the clipboard doesnt contain data, 当您从剪贴板获取数据时您的应用负责检查可用的 MIME 类型并决定使用哪种类型如果有 。
URI 如果ClipData.Item 是一个 URI getUri() 不为 null则 coerceToText() 会尝试将其作为内容 URI 使用 如果此 URI 是内容 URI并且提供程序可以返回文本流 则 coerceToText() 返回文本流 ,它会检查提供程序中是否有应用可以使用的 MIME 类型: 声明一个全局变量以包含 MIME 类型 // 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 ; 获取全局剪贴板,ClipDescription 对象的标签设置为 label, or issue an error if your application was expecting an Intent to be // on the clipboard } 使用Content Provider复制复杂的数据 注意 如需为您的应用设计有效的复制和粘贴功能请谨记以下几点 在任何时候剪贴板中都只能有一个剪切 。
MIME类型设置为 MIMETYPE_TEXT_INTENT。
label, 使用newUri()可从 URI 尤其是 content: URI创建剪切, 以下过程说明了如何基于剪贴板中的内容 URI 从 Content Provider 获取数据。
它 主要适用于从 Content Provider 复制复杂的数据 。
使用 newIntent() 可从 Intent 对象 创建剪切,不过 您可以向一个剪切添加多个 ClipData.Item 对象 , since the clipboard has data but it is not plain text pasteItem . setEnabled ( false ) ; } else { // This enables the paste menu item, null , null ) ; // If the Cursor contains data。
另外获取一个内容解析器以便您可以访问 Content Provider // Gets a handle to the Clipboard Manager ClipboardManager clipboard ( ClipboardManager ) getSystemService ( Context . CLIPBOARD_SERVICE ) ; // Gets a content resolver instance ContentResolver cr getContentResolver ( ) ; 从剪贴板中获取主要剪切并获取其内容作为 URI // Gets the clipboard data from the clipboard ClipData clip clipboard . getPrimaryClip ( ) ; if ( clip ! null ) { // Gets the first item from the clipboard data ClipData . Item item clip . getItemAt ( 0 ) ; // Tries to get the items contents as a URI Uri pasteUri item . getUri ( ) ; 通过调用 getType(Uri) 测试该 URI 是否为内容 URI,它支持简单和复杂的数据类型包括文本字符串、复杂数据结构、文本、二进制流数据甚至应用资源, copyUri ) ; —————————————————————————————————————————————————————— // Creates the Intent Intent appIntent new Intent ( this ,然后获取剪贴对象并使用 getText() 将其文本复制到您自己的存储空间如以下过程所述 使用 getSystemService(CLIPBOARD_SERVICE)获取全局 ClipboardManager 对象,如需粘贴数据您需要获取该剪贴对象然后将 Intent 对象复制到您应用的内存区域。
以下代码段演示了此过程 // Gets a handle to the Clipboard Manager ClipboardManager clipboard ( ClipboardManager ) getSystemService ( Context . CLIPBOARD_SERVICE ) ; // Checks to see if the clip item contains an Intent, ClipData、ClipData.Item 和 ClipDescription 如需将数据添加到剪贴板您需要创建一个 ClipData 对象其中包含数据的说明ClipDescription和数据本身ClipData.Item。
检索剪贴对象的元数据例如通过调用getPrimaryClipDescription()而非 getPrimaryClip()进行检索,ClipData 包含一个或多个 ClipData.Item 对象和一个 ClipDescription 对象, 粘贴纯文本 如需粘贴纯文本首先请获取全局剪贴板并验证它能否返回纯文本, Android 提供了一个强大的基于剪贴板的框架用于复制和粘贴, new Handler ( ) . postDelayed ( new Runnable ( ) { public void run ( ) { cm ( ClipboardManager ) MainActivity . this . getSystemService ( Context . CLIPBOARD_SERVICE ) ; if ( ! cm . hasPrimaryClip ( ) ) { return ; } //剪切板操作 . . . } ,当应用将一个剪贴对象放到剪贴板时上一个剪贴对象会消失, text) 返回一个ClipData 对象该对象的单个 ClipData.Item对象包含一个文本字符串, by testing to see if getIntent() returns null Intent pasteIntent clipboard . getPrimaryClip ( ) . getItemAt ( 0 ) . getIntent ( ) ; if ( pasteIntent ! null ) { // handle the Intent } else { // ignore the clipboard,由于用户可能会离开您的应用并在执行复制操作后返回因此您不能假设剪贴板中包含用户之前在您的应用中复制的剪切, try to get text from it if ( pasteUri ! null ) { // calls a routine to resolve the URI and get data from it. This routine is not // presented here. pasteData resolveUri ( Uri ) ; return true ; } else { // Something is wrong. The MIME type was plain text。
如果 Uri 不指向有效的 Content Provider则此方法会返回 null // If the clipboard contains a URI reference if ( pasteUri ! null ) { // Is this a content URI? String uriMimeType cr . getType ( pasteUri ) ; 测试 Content Provider 是否支持当前应用可以理解的 MIME 类型。
attempts to get data from it } else { Uri pasteUri item . getUri ( ) ; // If the URI contains something。
复制和粘贴既可以在应用内进行也可以在实现了该框架的应用之间进行, 获取系统剪贴板 // Gets a handle to the clipboard service. ClipboardManager clipboard ( ClipboardManager ) getSystemService ( Context . CLIPBOARD_SERVICE ) ; 将数据复制到新的 ClipData 对象 // Creates a new text clip to put on the clipboard ClipData clip ClipData . newPlainText ( simple text ,例如如果您有一个列表微件可让用户一次选择多个项则您可以同时将所有这些项复制到剪贴板,您 不能直接实例化此类 而是应通过 调用 getSystemService(CLIPBOARD_SERVICE)获取对它的引用 。
为此您需要分别为每个列表项创建一个 ClipData.Item然后将 ClipData.Item 对象添加到 ClipData 对象,粘贴应用可以检查该信息以了解自己能否处理该剪贴数据,您可以直接将字符串放入剪贴对象中然后将剪贴对象放到剪贴板中, 提供数据时您可以提供不同的 MIME 表示形式 ,如需复制数据您需要创建一个 Intent将其放入一个剪贴对象中然后将该剪贴对象放到剪贴板中, ClipData.Item对象包含 text、URI 或 intent 数据: Text 一个 文本字符串 ,另外声明一个全局变量以包含粘贴的文本 ClipboardManager clipboard ( ClipboardManager ) getSystemService ( Context . CLIPBOARD_SERVICE ) ; String pasteData ; 接下来确定您是否应在当前 Activity 中启用或停用“粘贴”选项, 将剪贴板数据强制转换为文本 即使您的应用仅处理文本您也可以从剪贴板复制非文本数据只需使用 ClipData.Item.coerceToText()方法对其进行转换即可, decide if you can handle the data. if ( ! ( clipboard . hasPrimaryClip ( ) ) ) { pasteItem . setEnabled ( false ) ; } else if ( ! ( clipboard . getPrimaryClipDescription ( ) . hasMimeType ( MIMETYPE_TEXT_PLAIN ) ) ) { // This disables the paste menu item。
since the clipboard contains plain text. pasteItem . setEnabled ( true ) ; } 从剪贴板复制数据。
使用newPlainText()可从 文本字符串 创建剪切。
您可以选择使用 coerceToText()如果已选择将剪贴板中的数据强制转换成文本,如需粘贴数据应用需要获取 ClipData从 ClipDescription 获取其 MIME 类型然后从 ClipData.Item 或 ClipData.Item 引用的 Content Provider 获取数据, null ,因此如果还需要监听剪切板可以使用应用生命周期回调监听APP后台返回延迟几毫秒访问剪切板再保存最后一次访问得到的剪切板内容每次都比较一下是否有变化再进行下一步操作, 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, move to the first record if ( pasteCursor ! null ) { if ( pasteCursor . moveToFirst ( ) ) { // get the data from the Cursor here. The code will vary according to the // format of the data model. } } // close the Cursor pasteCursor . close ( ) ; } } } } 粘贴 Intent 如需粘贴 Intent首先请获取全局剪贴板, Hello,如果您的应用支持多种可用的 MIME 类型您可以允许用户选择要使用哪一种, World! ) ; —————————————————————————————————————————————————————— // Creates a Uri based on a base Uri and a record ID based on the contacts last name // 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 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 objects label is URI,当您将一个剪切放到剪贴板中时系统会向粘贴应用提供此信息, ClipData.Item.coerceToText() 返回的值基于 ClipData.Item 中的数据的形式 Text 如果 ClipData.Item是一个 文本 getText() 不为 null则 coerceToText() 返回该文本 ,您通常希望一个剪切中的所有 ClipData.Item 对象都采用相同的形式也就是说它们应该都是简单文本、内容 URI 或 Intent而不是这些形式的混合。
如需粘贴数据您需要获取该剪贴对象获取 Uri 对象将其解析为数据源例如某个 Content Provider然后将数据从源中复制到应用的存储空间, 此外您可能还希望无论剪贴板中的数据采用何种形式用户都可以粘贴文本,如需复制数据您需要将一个 Uri 对象放入一个剪贴对象中并将该剪贴对象放到剪贴板中,该消息包含以下格式的文本 APP pasted from your clipboard 在应用执行以下某一项操作时系统不会显示消息框消息 通过您自己的应用访问 ClipData, 如果此 URI 不是内容 URI或者是内容 URI 但提供程序不提供文本流 则 coerceToText() 返回此 URI 的 Uri.toString() 返回的表示形式 , 剪切板框架 图 1 汇总了剪贴板框架。
注意 剪贴板一次只保留一个剪贴对象 , 通过特定应用反复访问ClipData,这让用户可以将多个选择复制和粘贴为一个剪切,返回值是 Cursor // If the return value is not null,任何应用在系统中执行的新的复制操作都会覆盖上一个剪切。
