Android应用开发之(通过ClipboardManager, ClipData进行复制粘贴)
在开发一些系统应用的时候,我们会用到Android的剪贴板功能,比如将文本文件、或者其他格式的内容复制到剪贴板或者从剪贴板获取数据等操作。Android平台中每个常规的应用运行在自己的进程空间中,相对于Win32而言Android上之间的进程间传递主要有IPC、剪切板。当然今天我们说下最简单的ClipboardManager。使用剪切板可以直接实现数据的传输。整个实现比较简单,注意剪切板中的类型判断。
使用起来很简单,系统给我们提供了很方便的接口,如下文本信息复制如下所示:
- //获取剪贴板管理服务
- ClipboardManager cm =(ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
- //将文本数据复制到剪贴板
- cm.setText(message);
- //读取剪贴板数据
- cm.getText();
- public void setClipboard(String text) {
- ClipboardManager clipboard = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);
- clipboard.setText(text);
- }
- public String getClipboard() {
- ClipboardManager clipboard = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);
- return clipboard.getText().toString();
- }
ClipData代表剪贴板中剪切数据。它有一个或多个Item实例,每个可容纳一个或多个数据项。 ClipData包含ClipDescription,用来描述剪贴内容的重要元数据。尤其是getDescription().getMimeType(INT)必须返回正确的MIME类型。为了正确的设置剪贴内容的MIME类型,建议使用newPlainText(CharSequence,CharSequence的),newUri(ContentResolver,CharSequence中,URI),newIntent(CharSequence, Intent)构造ClipData。每个Item的实例可以是三大数据类型之一:text,intent,URI。详情请参阅ClipData.Item
粘贴数据
为了获取剪贴板中的数据,应用程序必须正确解析数据;如果CipData.Item包含的信息为文本或者Intent类型,有一点需要说明:文本只能解析为文本,intent通常用来当中快捷方式或者其他的动作类型;如果你只是想获取文本内容,你可以通过Item.coerceToText()方法强制获取,这样就不需要考虑MIME类型,应为所有的item都会被强制转换为文本。
复杂的数据类型通常用URL来完成粘贴。允许接受者以URI方式从ContentProvider的获取数据。剪贴时需要填写正确的MIME类型; 如:newUri(ContentResolver,CharSequence,URI)这样才能被正确的处理。
下面是NotePad应用粘贴的例子。当从剪贴板中接受数据时,如果剪贴板中包含已有note的URI引用时,根据URI复制其结构到新的Note中,否则通过根据获取的文本内容作为新的笔记内容:
- /**
- * A helper method that replaces the note's data with the contents of the clipboard.
- */
- private final void performPaste() {
- // Gets a handle to the Clipboard Manager
- ClipboardManager clipboard = (ClipboardManager)
- getSystemService(Context.CLIPBOARD_SERVICE);
- // Gets a content resolver instance
- ContentResolver cr = getContentResolver();
- // Gets the clipboard data from the clipboard
- ClipData clip = clipboard.getPrimaryClip();
- if (clip != null) {
- String text=null;
- String title=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 pointing to a note
- Uri uri = item.getUri();
- // Tests to see that the item actually is an URI, and that the URI
- // is a content URI pointing to a provider whose MIME type is the same
- // as the MIME type supported by the Note pad provider.
- if (uri != null && NotePad.Notes.CONTENT_ITEM_TYPE.equals(cr.getType(uri))) {
- // The clipboard holds a reference to data with a note MIME type. This copies it.
- Cursor orig = cr.query(
- uri, // URI for the content provider
- PROJECTION, // Get the columns referred to in the projection
- null, // No selection variables
- null, // No selection variables, so no criteria are needed
- null // Use the default sort order
- );
- // If the Cursor is not null, and it contains at least one record
- // (moveToFirst() returns true), then this gets the note data from it.
- if (orig != null) {
- if (orig.moveToFirst()) {
- int colNoteIndex = mCursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_NOTE);
- int colTitleIndex = mCursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_TITLE);
- text = orig.getString(colNoteIndex);
- title = orig.getString(colTitleIndex);
- }
- // Closes the cursor.
- orig.close();
- }
- }
- // If the contents of the clipboard wasn't a reference to a note, then
- // this converts whatever it is to text.
- if (text == null) {
- text = item.coerceToText(this).toString();
- }
- // Updates the current note with the retrieved title and text.
- updateNote(text, title);
- }
- }
很多应用可以处理多种类型的数据,例如:E_mail应用希望用户粘贴图片或者其他二进制文件作为附件。这就需要通过ContentResolver的getStreamTypes(Uri, String)和openTypedAssetFileDescriptor(Uri,String,android.os.Bundle)方法处理。这需要客户端检测一个特定的内容URI以流的方式处理数据。
如下面是Item.coerceToText的实现:
- public CharSequence coerceToText(Context context) {
- // If this Item has an explicit textual value, simply return that.
- if (mText != null) {
- return mText;
- }
- // If this Item has a URI value, try using that.
- if (mUri != null) {
- // First see if the URI can be opened as a plain text stream
- // (of any sub-type). If so, this is the best textual
- // representation for it.
- FileInputStream stream = null;
- try {
- // Ask for a stream of the desired type.
- AssetFileDescriptor descr = context.getContentResolver()
- .openTypedAssetFileDescriptor(mUri, "text/*", null);
- stream = descr.createInputStream();
- InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
- // Got it... copy the stream into a local string and return it.
- StringBuilder builder = new StringBuilder(128);
- char[] buffer = new char[8192];
- int len;
- while ((len=reader.read(buffer)) > 0) {
- builder.append(buffer, 0, len);
- }
- return builder.toString();
- } catch (FileNotFoundException e) {
- // Unable to open content URI as text... not really an
- // error, just something to ignore.
- } catch (IOException e) {
- // Something bad has happened.
- Log.w("ClippedData", "Failure loading text", e);
- return e.toString();
- } finally {
- if (stream != null) {
- try {
- stream.close();
- } catch (IOException e) {
- }
- }
- }
- // If we couldn't open the URI as a stream, then the URI itself
- // probably serves fairly well as a textual representation.
- return mUri.toString();
- }
- // Finally, if all we have is an Intent, then we can just turn that
- // into text. Not the most user-friendly thing, but it's something.
- if (mIntent != null) {
- return mIntent.toUri(Intent.URI_INTENT_SCHEME);
- }
- // Shouldn't get here, but just in case...
- return "";
- }
复制数据
做为复制的源数据,应用要构造容易被接受解析的剪贴数据。如果要复制包含文本,Intent,或者URI,简单的方式是使用ClipData.Item包含相应的类型数据;
复杂的数据类型要求支持以ContentProvide方式描述和生成被接受的数据,常用的解决方案是以URI的方式复制数据,URI有复杂结构的数据组成,只有理解这种结果的应用才能接受处理这样的数据;
对于不具有内在的数据结构知识的应用,可使用任意可接受的数据流类型。这是通过实现ContentProvider的getStreamTypes(URI,String)和openTypedAssetFile(URI字符串,android.os.Bundle)方法进行获取。
回到记事本应用程序的例子,它是将要复制的内容以URI的传递的
- /**
- * This describes the MIME types that are supported for opening a note
- * URI as a stream.
- */
- static ClipDescription NOTE_STREAM_TYPES = new ClipDescription(null,
- new String[] { ClipDescription.MIMETYPE_TEXT_PLAIN });
- /**
- * Returns the types of available data streams. URIs to specific notes are supported.
- * The application can convert such a note to a plain text stream.
- *
- * @param uri the URI to analyze
- * @param mimeTypeFilter The MIME type to check for. This method only returns a data stream
- * type for MIME types that match the filter. Currently, only text/plain MIME types match.
- * @return a data stream MIME type. Currently, only text/plan is returned.
- * @throws IllegalArgumentException if the URI pattern doesn't match any supported patterns.
- */
- @Override
- public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
- /**
- * Chooses the data stream type based on the incoming URI pattern.
- */
- switch (sUriMatcher.match(uri)) {
- // If the pattern is for notes or live folders, return null. Data streams are not
- // supported for this type of URI.
- case NOTES:
- case LIVE_FOLDER_NOTES:
- return null;
- // If the pattern is for note IDs and the MIME filter is text/plain, then return
- // text/plain
- case NOTE_ID:
- return NOTE_STREAM_TYPES.filterMimeTypes(mimeTypeFilter);
- // If the URI pattern doesn't match any permitted patterns, throws an exception.
- default:
- throw new IllegalArgumentException("Unknown URI " + uri);
- }
- }
- /**
- * Returns a stream of data for each supported stream type. This method does a query on the
- * incoming URI, then uses
- * {@link android.content.ContentProvider#openPipeHelper(Uri, String, Bundle, Object,
- * PipeDataWriter)} to start another thread in which to convert the data into a stream.
- *
- * @param uri The URI pattern that points to the data stream
- * @param mimeTypeFilter A String containing a MIME type. This method tries to get a stream of
- * data with this MIME type.
- * @param opts Additional options supplied by the caller. Can be interpreted as
- * desired by the content provider.
- * @return AssetFileDescriptor A handle to the file.
- * @throws FileNotFoundException if there is no file associated with the incoming URI.
- */
- @Override
- public AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts)
- throws FileNotFoundException {
- // Checks to see if the MIME type filter matches a supported MIME type.
- String[] mimeTypes = getStreamTypes(uri, mimeTypeFilter);
- // If the MIME type is supported
- if (mimeTypes != null) {
- // Retrieves the note for this URI. Uses the query method defined for this provider,
- // rather than using the database query method.
- Cursor c = query(
- uri, // The URI of a note
- READ_NOTE_PROJECTION, // Gets a projection containing the note's ID, title,
- // and contents
- null, // No WHERE clause, get all matching records
- null, // Since there is no WHERE clause, no selection criteria
- null // Use the default sort order (modification date,
- // descending
- );
- // If the query fails or the cursor is empty, stop
- if (c == null || !c.moveToFirst()) {
- // If the cursor is empty, simply close the cursor and return
- if (c != null) {
- c.close();
- }
- // If the cursor is null, throw an exception
- throw new FileNotFoundException("Unable to query " + uri);
- }
- // Start a new thread that pipes the stream data back to the caller.
- return new AssetFileDescriptor(
- openPipeHelper(uri, mimeTypes[0], opts, c, this), 0,
- AssetFileDescriptor.UNKNOWN_LENGTH);
- }
- // If the MIME type is not supported, return a read-only handle to the file.
- return super.openTypedAssetFile(uri, mimeTypeFilter, opts);
- }
- /**
- * Implementation of {@link android.content.ContentProvider.PipeDataWriter}
- * to perform the actual work of converting the data in one of cursors to a
- * stream of data for the client to read.
- */
- @Override
- public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType,
- Bundle opts, Cursor c) {
- // We currently only support conversion-to-text from a single note entry,
- // so no need for cursor data type checking here.
- FileOutputStream fout = new FileOutputStream(output.getFileDescriptor());
- PrintWriter pw = null;
- try {
- pw = new PrintWriter(new OutputStreamWriter(fout, "UTF-8"));
- pw.println(c.getString(READ_NOTE_TITLE_INDEX));
- pw.println("");
- pw.println(c.getString(READ_NOTE_NOTE_INDEX));
- } catch (UnsupportedEncodingException e) {
- Log.w(TAG, "Ooops", e);
- } finally {
- c.close();
- if (pw != null) {
- pw.flush();
- }
- try {
- fout.close();
- } catch (IOException e) {
- }
- }
- }
not复制操作现在只是简单的构造UPI:
- case R.id.context_copy:
- // Gets a handle to the clipboard service.
- ClipboardManager clipboard = (ClipboardManager)
- getSystemService(Context.CLIPBOARD_SERVICE);
- // Copies the notes URI to the clipboard. In effect, this copies the note itself
- clipboard.setPrimaryClip(ClipData.newUri( // new clipboard item holding a URI
- getContentResolver(), // resolver to retrieve URI info
- "Note", // label for the clip
- noteUri) // the URI
- );
- // Returns to the caller and skips further processing.
- return true;
注 如果粘贴操作需要文本(例如粘贴到编程器中)coerceToText(Context)方式会通知内容提供者将URI转换为URL;
Android应用开发之(通过ClipboardManager, ClipData进行复制粘贴)的更多相关文章
- Android 复制 粘贴 剪贴板的使用 ClipboardManager
Copy and Paste 版本:Android 4.0 r1 快速查看 用于复制粘贴数据的基于剪贴板的框架. 同时支持简单和复杂的数据,包括文本串.复杂的数据结构.文本和二进制流数据.程序 as ...
- Android N开发 你需要知道的一切
title: Android N开发 你需要知道的一切 tags: Android N,Android7.0,Android --- 转载请注明出处:http://www.cnblogs.com/yi ...
- Android游戏开发实践(1)之NDK与JNI开发03
Android游戏开发实践(1)之NDK与JNI开发03 前面已经分享了两篇有关Android平台NDK与JNI开发相关的内容.以下列举前面两篇的链接地址,感兴趣的可以再回顾下.那么,这篇继续这个小专 ...
- Android游戏开发实践(1)之NDK与JNI开发01
Android游戏开发实践(1)之NDK与JNI开发01 NDK是Native Developement Kit的缩写,顾名思义,NDK是Google提供的一套原生Java代码与本地C/C++代码&q ...
- Android游戏开发实践(1)之NDK与JNI开发02
Android游戏开发实践(1)之NDK与JNI开发02 承接上篇Android游戏开发实践(1)之NDK与JNI开发01分享完JNI的基础和简要开发流程之后,再来分享下在Android环境下的JNI ...
- 【转】Android 底层开发的几点
我干了3年Android sdk开发,觉得到了瓶劲没法更进一步,于是花了一年多点时间,大概摸到点门径.根据前辈的经验,Android底层完全入门需要两年. 先说下我的入门过程:第零步,下载源码,我下的 ...
- 《Android NFC 开发实战详解 》简介+源码+样章+勘误ING
<Android NFC 开发实战详解>简介+源码+样章+勘误ING SkySeraph Mar. 14th 2014 Email:skyseraph00@163.com 更多精彩请直接 ...
- Android安全开发之安全使用HTTPS
Android安全开发之安全使用HTTPS 1.HTTPS简介 阿里聚安全的应用漏洞扫描器中有证书弱校验.主机名弱校验.webview未校验证书的检测项,这些检测项是针对APP采用HTTPS通信时容易 ...
- Android安全开发之通用签名风险
Android安全开发之通用签名风险 作者:伊樵.舟海.呆狐@阿里聚安全 1 通用签名风险简介 1.1 Android应用签名机制 阿里聚安全漏洞扫描器有一项检测服务是检测APP的通用签名风险.And ...
随机推荐
- 17.1.1.7 Setting Up Replication with New Master and Slaves 设置复制对于新的Master和Slaves:
17.1.1.7 Setting Up Replication with New Master and Slaves 设置复制对于新的Master和Slaves: 最简单和最直接的方法是设置复制用于使 ...
- MFC全局函数开局——AfxGetApp解剖
MFC中有不少的全局函数,方便在不同对象中获取不同的内容或创建不同的对象.主要全局函数有: AfxWinInit() AfxBeginThread() AfxEndThread() AfxFormat ...
- JVM调优总结(七)-典型配置举例1
以下配置主要针对分代垃圾回收算法而言. 堆大小设置 年轻代的设置很关键 JVM中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理 ...
- IE浏览器下web调试工具之--IE WebDeveloper介绍
做Web项目的架构设计.开发.测试,免不了要熟悉Web页面调试工具,以此来获知哪些浏览器支持Web页面的显示,哪些浏览器下显示有问题. 目前市面上比较火爆的浏览器内核提供商,有微软的IE.mozill ...
- ORA-19815,ORA-19809 :limit exceeded for recovery files
数据库重新启动的时候,收到了ORA-19815的错误.从错误的提示来看,是由于闪回区的空间被填满导致无法成功启动.这种情形我们通常考虑的是清除归档日志,那就直接在OS层面rm了,真的是这样吗?客官,如 ...
- 8 cocos2dx加入场景切换效果,控制场景切换彻底完毕之后再运行动画
1 加入场景切换效果 供场景切换的类: CCTransitionJumpZoom CCTransitionProgressRadialCCW CCTransitionProgressRadial ...
- git项目同时支持多个远端仓库
git项目同时支持多个远端仓库 为了防止github被墙,最好在国内的托管商做一个备份,这就需要同时提交到多个远端仓库,例如一个open source项目同时要提交csdn和github,url分别是 ...
- linux系统挂掉问题的分析
玩linux系统,经常遇到的一件事就是做了某个操作之后系统会突然挂掉,这要怎么办? 1. 首先我们要看log,看看是否会留下一些蛛丝马迹,比如PC/LR是否有留下来. PC是ARM的一个寄存器,即程序 ...
- Eclipse用法和技巧六:自动生成get和set方法1
java的类中,除了常量声明为静态且公有的,一般的对象数据作用域,都是声明为私有的.这样做能保护对象的属性不会被随意改变,调试的时候也会方便很多:在类的公有方法中大一个调用栈就能看到哪里改了属性值.声 ...
- MFC类中获得其它类指针
当用VC++的Application Wizard生成除了CDialog Basiced以外的应用程序时,将自动产生视图类.文档类.主帧窗口类.应用程序类等等.一般来说,程序的核心数据及操作在文档类中 ...