课程概述
剪贴板上剪切数据的表示。
ClippedData是包含一个或Item实例的复杂类型,其中的每一个可以保存数据项的一个或多个表示。为了向用户显示,它还具有标签和图标表示。
ClipData包含剪辑描述
,它描述了有关剪辑的重要元数据。特别是,它的getDescription().getMimeType(int)
必须返回描述剪辑中数据的正确MIME类型。寻求帮助在正确构造具有正确MIME类型的剪辑时,请使用newPlainText(字符序列,字符序列)
,newUri(ContentResolver,CharSequence,Uri)
、和newIntent(CharSequence,Intent)
。
每个Item实例可以是三个主要数据类之一:一个简单的文本、单个Intent对象或Uri的CharSequence。请参阅剪辑数据。项目
了解更多详细信息。
开发人员指南
有关使用剪贴板框架的更多信息,请阅读复制和粘贴开发人员指南。
实现粘贴或删除
要将ClippedData对象粘贴或拖放到应用程序中,应用程序必须正确解释数据以供使用。如果剪辑数据。项目
它包含简单的文本或意图,没有什么可做的:文本只能解释为文本,Intent通常用于创建快捷方式(例如在主屏幕上放置图标)或其他行动。
如果您只需要裁剪数据的文本表示,那么您可以可以使用方便的方法项目引用到文本
。在这种情况下,通常不需要担心MIME类型报告人getDescription().getMimeType(int)
,因为任何剪辑项都会转换为字符串。
更复杂的交换将通过URI完成,尤其是“content:”URI。内容URI允许ClippedData项的收件人与持有数据的ContentProvider密切互动,以便协商数据的传输。夹子中还必须填入可用的MIME类型;newUri(ContentResolver,CharSequence,Uri)
将负责正确执行此操作。
例如,这里是一个简单的记事本应用程序的粘贴功能。从剪贴板检索数据时,它可以执行以下两项操作之一:如果剪贴板包含对现有注释的URI引用,则会复制将音符的整个结构转换为新的音符;否则,它只是将剪辑强制转换为文本,并将其用作新注释的内容。
/***用剪贴板的内容替换注释数据的帮助器方法。*/private final void performPaste(){//获取剪贴板管理器的句柄ClipboardManager剪贴板=(clipboard Manager)获取系统服务(Context.CLIPBOARD_SERVICE);//获取内容解析程序实例内容解析器cr=getContentResolver();//从剪贴板获取剪贴板数据ClipData clip=剪贴板.getPrimaryClip();if(clip!=空){字符串文本=空;字符串标题=空;//从剪贴板数据中获取第一项剪辑数据。项目项=clip.getItemAt(0);//尝试以指向注释的URI的形式获取项目的内容Uri Uri=item.getUri();//测试项目是否实际是URI,以及URI//是指向MIME类型相同的提供程序的内容URI//作为记事本提供程序支持的MIME类型。if(uri!=null&&NotePad.Notes.CONTENT_ITEM_TYPE.equals(cr.getType(uri)){//剪贴板保存对注释MIME类型数据的引用。这复制了它。光标orig=cr.query(uri,//内容提供者的uriPROJECTION,//获取投影中引用的列null,//无选择变量null,//没有选择变量,因此不需要条件null//使用默认排序顺序);//如果游标不为空,并且它至少包含一条记录//(moveToFirst()返回true),然后从中获取音符数据。if(orig!=空){if(orig.moveToFirst()){int colNoteIndex=mCursor.getColumnIndex(记事本.Notes.COLUMN_NAME_NOTE);int colTitleIndex=mCursor.getColumnIndex(记事本.Notes.COLUMN_NAME_TITLE);text=orig.getString(colNoteIndex);title=orig.getString(colTitleIndex);}//关闭光标。原始关闭();}}//如果剪贴板的内容不是对注释的引用,那么//这会将任何内容转换为文本。if(文本==空){text=item.corenceToText(this).toString();}//使用检索到的标题和文本更新当前注释。updateNote(文本、标题);}}
在许多情况下,应用程序可以粘贴各种类型的数据流。对于例如,电子邮件应用程序可能希望允许用户粘贴图像或其他二进制数据作为附件。这是通过内容解析器getStreamTypes(Uri,字符串)
和openTypedAssetFileDescriptor(Uri、字符串、android.os.Bundle)
方法。这些允许客户端发现特定内容URI可以作为流使用并检索数据流。
例如项目引用到文本
它本身使用此函数尝试将URI片段作为文本流检索:
public CharSequence强制ToText(上下文上下文){//如果此项具有显式文本值,只需返回该值。CharSequence text=getText();if(文本!=空){返回文本;}//如果此项有URI值,请尝试使用该值。Uri Uri=获取Uri();if(uri!=空){//首先看看URI是否可以作为纯文本流打开//(任何子类型)。如果是这样,这是最好的文本//代表它。FileInputStream流=null;尝试{//要求提供所需类型的流。AssetFileDescriptor descr=context.getContentResolver().openTypedAssetFileDescriptor(uri,“text/*”,null);流=descr.createInputStream();InputStreamReader阅读器=新的InputStreamReader(流,“UTF-8”);//明白了……将流复制到本地字符串中并返回它。StringBuilder builder=新的String builder(128);char[]buffer=新char[8192];整数长度;while((len=reader.read(buffer))>0){builder.append(缓冲区,0,长度);}return builder.toString();}catch(FileNotFoundException e){//无法以文本形式打开内容URI。。。不是真的//错误,只是一些可以忽略的东西。}捕获(IOException e){//发生了不好的事情。Log.w(“ClippedData”,“Failure loading text”,e);返回e.toString();}最后{if(流!=空){尝试{stream.close();}捕获(IOException e){}}}//如果我们无法将URI作为流打开,那么URI本身//作为文本表示,它可能相当有用。return uri.toString();}//最后,如果我们只有一个意向,那么我们就可以扭转这种局面//到文本中。这不是最人性化的东西,但它确实很重要。意向=getIntent();if(意图!=空){return intent.toUri(intent.URI_intent_SCHEME);}//不应该到这里,但以防万一。。。返回“”;}
执行复制或拖动
要成为剪辑的源,应用程序必须构造ClippedData任何接收者都可以根据其上下文最佳解释的对象。如果夹子是包含简单文本、Intent或URI,这很简单:剪辑数据。项目
可以构造和使用包含适当数据类型的。
更复杂的数据类型需要在中实现支持内容提供者,用于描述和生成用于所述接收方的所述数据。常见的情况是,应用程序将content:用户复制的对象的URI,包含该位置的数据URI由一个复杂的结构组成,只有其他应用程序才具有直接了解结构可以使用。
对于不具备数据结构固有知识的应用程序,持有它的内容提供者可以使数据作为任意数据提供数据流类型的数量。这是通过实现内容提供者getStreamTypes(Uri,字符串)
和openTypedAssetFile(Uri、字符串、android.os.Bundle)
方法。
回到我们简单的记事本应用程序,这是它的实现它可能必须转换单个注释URI(由标题和注释组成文本)转换为纯文本数据流。
/***这描述了打开便笺时支持的MIME类型*URI作为流。*/static ClipDescription NOTE_STREAM_TYPES=新剪辑描述(空,新字符串[]{ClipDescription.MIMETYPE_TEXT_PLAIN});/***返回可用数据流的类型。支持特定注释的URI。*应用程序可以将此类注释转换为纯文本流。**@param uri要分析的uri*@param mimeTypeFilter要检查的MIME类型。此方法仅返回数据流*与筛选器匹配的MIME类型的类型。目前,只有文本/纯MIME类型匹配。*@return数据流MIME类型。目前,只返回文本/计划。*如果URI模式与任何支持的模式都不匹配,@throws IllegalArgumentException。*/@覆盖public String[]getStreamTypes(Uri Uri,String mimeTypeFilter){/***根据传入的URI模式选择数据流类型。*/开关(sUriMatcher.match(uri)){//如果该模式用于笔记或活动文件夹,则返回null。数据流不是//支持此类型的URI。案例注释:案例LIVE_FOLDER_NOTES:返回null;//如果模式用于注释ID,并且MIME过滤器为text/plain,则返回//文本/纯文本案例NOTE_ID:return NOTE_STREAM_TYPES.filterMimeTypes(mimeTypeFilter);//如果URI模式与任何允许的模式都不匹配,则抛出异常。违约:抛出新的IllegalArgumentException(“未知URI”+URI);}}/***返回每个支持流类型的数据流。此方法对*传入URI,然后使用*{@link android.content.ContentProvider#openPipeHelper(Uri,String,Bundle,Object,*PipeDataWriter)}启动另一个线程,在其中将数据转换为流。**@param uri指向数据流的uri模式*@param mimeTypeFilter包含MIME类型的字符串。此方法尝试获取*此MIME类型的数据。*@param opts调用方提供的其他选项。可以解释为*内容提供商所期望的。*@return AssetFileDescriptor文件的句柄。*如果没有与传入URI关联的文件,则返回@throws FileNotFoundException。*/@覆盖public AssetFileDescriptor openTypedAssetFile(Uri Uri,String mimeTypeFilter,Bundle opts)抛出FileNotFoundException{//检查MIME类型筛选器是否与支持的MIME类型匹配。String[]mimeTypes=getStreamTypes(uri,mimeTypeFilter);//如果支持MIME类型if(mimeTypes!=空){//检索此URI的注释。使用为此提供程序定义的查询方法,//而不是使用数据库查询方法。光标c=查询(uri,//注释的uriREAD_NOTE_PROJECTION,//获取包含注释ID、标题、,//和内容null,//无WHERE子句,获取所有匹配的记录null,//因为没有WHERE子句,所以没有选择条件null//使用默认排序顺序(修改日期,//下降);//如果查询失败或光标为空,请停止如果(c==null||!c.moveToFirst()){//如果光标为空,只需关闭光标并返回如果(c!=空){c.关闭();}//如果游标为空,则引发异常抛出新的FileNotFoundException(“无法查询”+uri);}//启动一个新线程,将流数据通过管道传回调用方。返回新的AssetFileDescriptor(openPipeHelper(uri,mimeTypes[0],opts,c,this),0,资产文件描述符。未知长度);}//如果不支持MIME类型,请返回该文件的只读句柄。return super.openTypedAssetFile(uri,mimeTypeFilter,opts);}/***{@link android.content.ContentProvider.PipeDataWriter}的实现*执行将一个游标中的数据转换为*客户端要读取的数据流。*/@覆盖public void writeDataToPipe(ParcelFileDescriptor输出,Uri-Uri,String mimeType,捆绑选项,光标c){//我们目前只支持从单个注释条目转换为文本,//所以这里不需要进行游标数据类型检查。FileOutputStream fout=新文件输出流(output.getFileDescriptor());PrintWriter pw=空;尝试{pw=新的PrintWriter(新的OutputStreamWriter,fout,“UTF-8”);pw.println(c.getString(READ_NOTE_TITLE_INDEX));pw.println(“”);pw.println(c.getString(READ_NOTE_NOTE_INDEX));}catch(不支持的编码异常e){日志.w(TAG,“Ooops”,e);}最后{c.关闭();if(pw!=空){pw.flush();}尝试{fout.close();}捕获(IOException e){}}}
记事本应用程序中的复制操作现在很简单制作包含所复制笔记URI的剪辑:
案例R.id.context_copy://获取剪贴板服务的句柄。ClipboardManager剪贴板=(clipboard Manager)获取系统服务(Context.CLIPBOARD_SERVICE);//将注释URI复制到剪贴板。实际上,这复制了注释本身clipboap.setPrimaryClip(ClipData.newUri(//新的剪贴板项,包含URIgetContentResolver(),//用于检索URI信息的resolver“注释”,//剪辑标签noteUri)//URI);//返回调用方并跳过进一步处理。返回true;
注意粘贴操作是否需要将此剪辑作为文本(例如粘贴进入编辑器),然后强制到文本(上下文)
将询问内容提供程序将剪辑URI作为文本并成功粘贴整个注释。