Android Clipboard 详解

Android 提供了一个强大的剪贴板框架,用于复制和粘贴。 它支持文本、二进制数据流或其它复杂的数据。

Android 剪贴板框架如图 copy_paste_framework

从图中可以看出,Android 剪贴板框架主要涉及到 ClipboardManagerClipDataClipData.ItemClipDescription 这四个类。

关于这四个类的简介如下:

  1. ClipboardManager 是系统全局的剪贴板对象,通过 context.getSystemService(CLIPBOARD_SERVICE) 获取。
  2. ClipData ,即 clip 对象,在系统剪贴板里只存在一个,当另一个 clip 对象进来时,前一个 clip 对象会消失。
  3. ClipData.Item ,即 data item,它包含了文本、 Uri 或者 Intent 数据,一个 clip 对象可以包含一个或多个 Item 对象。通过 addItem(ClipData.Item item) 可以实现往 clip 对象中添加 Item。
    • 文本:文本是直接放在 clip 对象中,然后放在剪贴板里;粘贴这个字符串的时候直接从剪贴板拿到这个对象,把字符串放入你的应用存储中。
    • Uri:对于复杂数据的剪贴拷贝并不是直接将数据放入内存,而是通过 Uri 来实现,毕竟 Uri 的中文名叫:统一资源标识符。通过 Uri 能定位手机上所有资源,这当然能实现拷贝了,只不过需要做一些额外的处理工作。(对于 Uri 不是很理解,如有误,望指正~)
    • Intent:复制的时候 Intent 会被直接放入 clip 对象,这相当于拷贝了一个快捷方式。
  4. ClipDescription ,即 clip metadata,它包含了 ClipData 对象的 metadata 信息。可以通过 getMimeType(int index) 获取(一般 index = 0,有兴趣的可以去看下 ClipData 的源码)。MimeType 一般有以下四种类型:

    MIMETYPE_TEXT_URILIST 有点特殊,当 Uri 为 content://uri 时,它会转为具体的 MimeType ,后面会有例子讲到。

剪贴板简单使用

以拷贝文本为例,剪贴板的使用可以分为以下几步:

  1. 获取 ClipManager 对象
  2. 将数据放到 clip 对象中

    类似的方法还有
  3. 将 clip 对象放入剪贴板
  4. 从剪贴板中获取 clip 对象

实践出真知

讲道理,实践出真知,咱们程序员的实践就是代码,下面上代码。等等,先上 Demo 的运行效果图。第一次做 Gif ,好紧张,哈哈~若动态图不动,查看原图连接应该就可以了~ demo

对于剪贴板大部分操作都封装在 ClipboardUtil.java 里,使用时请记录调用 init(Context context) 方法进行初始化,建议在 Application.onCreate() 中进行,否则会造成内存泄漏。

AndroidManifest.xml:

ClipboardApplication.java:

build.gradle:

MainActivity.java:

ClipboardUtil.java:

补充

以下补充几点,是自己在测试剪贴板的过程中碰到,一是 OnPrimaryClipChangedListener 的多次回调,二是将剪贴板中的内容转换为字符串。

关于 OnPrimaryClipChangedListener 的多次回调

细心的同学可能已经发现,上述代码中,楼主并没有直接使用 Android 的 OnPrimaryClipChangedListener ,而是自己对此进行了再次封装。这是有原因的,在最初测试剪贴板的过程中,楼主发现一次拷贝过程可能会导致多次回调 onPrimaryClipChanged() 方法,日志如下:

这肯定不是我们想要的结果,那么该怎么解决这个问题呢?

多次测试发现,发生多次回调的情况下,正确的拷贝结果都是最后一次回调获取到的数据。

再打印一下 onPrimaryClipChanged() 回调时间吧,发现三次的间隔不超过 9ms ,而普通用户一般不可能在如此短时间内完成多次拷贝。故我们可以定义一个变量存储 onPrimaryClipChanged 的回调时间,当下次回调时相对前一次的时间间隔小于 100ms(合理假设),那么判定前一次回调事件无效。

故才有了上诉的代码。

将剪贴板中的数据强转为字符串

一般来说,平时我们拷贝的都是文字,但是从上述内容可知,Android 剪贴板支持的不仅仅是文字,那对于 Uri 、 Intent 数据 Android 是如何把它们转换成字符串的呢?有兴趣的同学可以去查看 ClipData 下述三个方法的源码。这里限于篇幅就不详述了。

画外:如何高效的复制粘贴

此部分内容原文见 Android 官方文档 Copy and paste 最后一节,翻译摘自 Android中的复制粘贴

为了设计有效的复制粘贴功能,以下几点需要注意:

  1. 任何时间,都只有一个clip对象在剪贴板里。新的复制操作都会覆盖前一个clip对象,因为用户可能从你的应用中退出,从其他应用中拷贝一个东西,所以你不能假定用户在你的应用中拷贝的上一个东西一定还放在剪贴板里。
  2. 一个clip对象,即ClipData中的多个ClipData.Item 对象是为了支持多选项的复制粘贴,而不是为了支持单选的多种形式。你通常需要clip对象中的所有的项目,即ClipData.Item有一样的形式,比如都是文字,都是URI或都是Intent,而不是混合各种形式。
  3. 当你提供数据时,你可以提供不同的MIME表达方式。将你支持的MIME类型加入到ClipDescription中去,然后在你的content provider中实现它。
  4. 当你从剪贴板得到数据时,你的应用有责任检查可用的MIME类型,然后决定使用哪一个。即便有一个clip对象在剪贴板中并且用户要求粘贴,你的应用有可能不需要进行粘贴操作。你应该在MIME类型兼容的时候执行粘贴操作。你可以选择使用 coerceToText()方法将粘贴的内容转换为文字。如果你的应用支持多种类型,你可以让用户自己选用哪一个。

参考

  1. Copy and paste
  2. Android中的复制粘贴

版权声明:本文为博主原创文章,未经博主允许不得转载。 微博:厉圣杰 源码:AndroidDemo/Clipboard 如本文有助于你理解 Android 剪贴板,不妨给我一个 Star。对于码农而言,Star 是我们分享的动力~ 文中如有纰漏,欢迎大家留言指出。

1 1 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部