Android复制粘贴详解
一、复制与粘贴框架
1.概览
Android提供了一个基于剪切板的复制粘贴框架。支持字符串、复杂数据结构、文本与二进制数据流,以及应用assets的剪切。只有文本可直接存储到剪切板,其他存储为content provider。剪切板支持Text、URI、Intent三种形式的剪切对象。看到这三个,就大概知道了该怎么解析出需要的数据了。剪切板一次仅存储一个剪切对象,再存储另一个,之前的则会消失。
2.重要类与方法
类:
ClipboardManager:代表系统剪切板,通过getSystemService(CLIPBOARD_SERVICE)来获取实例。
ClipData:剪切板一次只包含一个ClipData,ClipData包含一个ClipDescription以及若干个ClipData.Item。
ClipDescription:包含关于剪切的元数据。包含了一组关于剪切数据的MIME类型。
ClipData.Item:包含文本(字符串),URI(一般是content provider URI),Intent(应用快捷方式)。
方法:
newPlainText(label, text):返回ClipData,有一个ClipData.Item,包含一个字符串。ClipDescription对象label属性即为label参数。其MIME
类型为MIMETYPE_TEXT_PLAIN;
newUri(resolver, lable, URI):返回ClipData,有一个ClipData.Item,包含一个URI。label与上述一样,如果URI是content URI,方法使用resolver从content provider获取MIME类型并存储在ClipDescription中。如果不是content URI,其MIME类型则为MIMETYPE_TEXT_URILIST;
newIntent(label, intent):返回ClipData,有一个ClipData.Item,包含一个Intent。label与上述一样,MIME类型为MIMETYPE_TEXT_INTENT。
ClipData.Item.coerceToText():将ClipData.Item中的数据强转为text。具体如下:
如果本身就是Text,则返回该Text;
如果是URI,a.如果是content URI且provider可以返回text stream,则返回text stream;b.如果是content URI,但没有text stream,则返回URI.toString();c.如果不是content URI,也返回URI.toString()。
如果是Intent,将会强转为Intent URI并返回,即Intent.toUri(URI_INTENT_SCHEME)。
具体的剪切板框架如下图所示。
3.剪切板框架原理
复制数据时,将ClipData对象放到ClipboardManager全局剪切板上。其包含了若干ClipData.Item以及一个ClipDescription。
粘贴数据时,应用获取ClipData,再获从ClipDescription获取其MIME类型,之后可以从ClipData.Item或者被其引用的content provider获取数据。
二、使用
1.复制
// 获取clipboard service句柄ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);// 复制文本ClipData clip = ClipData.newPlainText("simple text", "Hello, World!");// 创建Uri,本例中是联系人记录ID以及名称URIprivate static final String CONTACTS = "content://com.example.contacts";private static final String COPY_PATH = "/copy";Uri copyUri = Uri.parse(CONTACTS + COPY_PATH + "/" + lastName);// 复制URI对象。使用匿名getContentResolver()对象从provider中获取MIME类型ClipData clip = ClipData.newUri(getContentResolver(), "URI", copyUri);// 创建IntentIntent appIntent = new Intent(this, com.example.demo.myapplication.class);// 复制Intent对象,设置IntetClipData clip = ClipData.newIntent("Intent", appIntent);// 设置剪切板主要剪辑clipboard.setPrimaryClip(clip);
2.粘贴
1)获取ClipboardManager service
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);String pasteData = "";
2)根据剪切板是否含有数据以及数据类型是否可处理,决定是否启用粘贴
// 获取粘贴按钮MenuItem mPasteItem = menu.findItem(R.id.menu_paste);// 如果剪切板不包含数据,则禁用粘贴按钮,如果包含数据,要判断是否可以处理if (!(clipboard.hasPrimaryClip())) { mPasteItem.setEnabled(false);} else if (!(clipboard.getPrimaryClipDescription().hasMimeType(MIMETYPE_TEXT_PLAIN))) { // 如果有数据,但是不是文本,则不可粘贴 mPasteItem.setEnabled(false);} else { // 如果有数据且是文本,则可粘贴 mPasteItem.setEnabled(true);}
3)粘贴文本
// 检查item,如果getText不为空,则包含文本。 ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0);// 获取文本pasteData = item.getText();// 如果存在文本则粘贴可以进行if (pasteData != null) { return;// 如果存在的是URI,就要看其是否包含数据 If it contains a URI, attempts to get data from it} else { Uri pasteUri = item.getUri(); // 如果包含信息,则尝试从中获取文本 if (pasteUri != null) { // 解析URI,获取数据 pasteData = resolveUri(Uri); return; } else { // 没有信息,如果MIME是文本类型,但是不包含文本或Uri,则提示错误 Log.e("Clipboard contains an invalid data type"); return; }}
4)粘贴content URI
// 声明一个匹配provider提供的MIME类型的常量public static final String MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact";ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);// 获取ContentResolverContentResolver cr = getContentResolver();// 从剪切板获取clipboardDataClipData clip = clipboard.getPrimaryClip();if (clip != null) { // 获取clipboardData的第一个item ClipData.Item item = clip.getItemAt(0); // 尝试获取Uri Uri pasteUri = item.getUri(); // 如果存在Uri if (pasteUri != null) { // 如果存在content Uri String uriMimeType = cr.getType(pasteUri); if (uriMimeType != null) { // 判断其MIME类型是否当前应用可用 if (uriMimeType.equals(MIME_TYPE_CONTACT)) { // 从content provider获取数据. Cursor pasteCursor = cr.query(uri, null, null, null, null); if (pasteCursor != null) { if (pasteCursor.moveToFirst()) { // 获取数据 } } pasteCursor.close(); } } }}
5)粘贴Intent
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);// 检测clip是否包含IntentIntent pasteIntent = clipboard.getPrimaryClip().getItemAt(0).getIntent();if (pasteIntent != null) { // 处理Intent} else { // ...}
3.附加
一般应用只需要复制粘贴文本的功能,这里有一个工具:
public class ClipboardUtils { public static final String DATA = "data"; /** * 复制到剪切板 * @param context context * @param label 标签 * @param string 内容 */ public static void copy(Context context, String label, String string) { ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); clipboardManager.setPrimaryClip(ClipData.newPlainText(label != null ? label : DATA, string)); } /** * 从剪切板取出 * @param context context * @return 剪切板里的内容 */ public static String paste(Context context) { ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); ClipData clipData = clipboardManager.getPrimaryClip(); return clipData.getItemAt(0).toString(); }}
更多相关文章
- 为什么要学习 Markdown?究竟有什么用?
- “罗永浩抖音首秀”销售数据的可视化大屏是怎么做出来的呢?
- Nginx系列教程(三)| 一文带你读懂Nginx的负载均衡
- 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
- android调用MySQL时遇到的一些问题
- Android数据存储总结 之二
- Android之数据统计
- Android采用SharedPreferences方式进行文件的保存与读取
- Android实训案例(五)——四大组件之一ContentProvider的使用,通讯录