Android开发者指南-复制与粘贴-Copy and Paste[原创译文]

本文深入探讨了Android系统中复制与粘贴功能的实现原理及应用技巧,包括使用剪贴板框架、创建和操作ClipData、ClipDescription与ClipData.Item等关键类,以及如何在不同场景下灵活运用文本、URI、Intent等数据类型。文章还提供了实例代码,帮助开发者理解如何在实际项目中集成这些功能,以提升用户体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Copy and Paste

版本:Android 4.0 r1

 快速查看

  • 用于复制粘贴数据的基于剪贴板的框架。
  • 同时支持简单和复杂的数据,包括文本串、复杂的数据结构、文本和二进制流数据、程序 asset
  • 直接从剪贴板复制粘贴简单文本。
  • content provider复制粘贴复杂数据。
  • 需要API 11版本。

在本文中

剪贴板框架

剪贴板类

ClipboardManager

ClipData、ClipDescription和ClipData.Item

ClipData常用方法

将剪贴板中数据强制转换为文本

复制到剪贴板中

从剪贴板中粘贴

复制到剪贴板中

粘贴普通文本

从content URI粘贴数据

粘贴Intent

利用Content Provider复制复杂数据

将ID置入URI编码

复制数据结构

复制数据流

设计高效的复制/粘贴功能

关键类

ClipboardManager

ClipData

ClipData.Item

ClipDescription

Uri

ContentProvider

Intent

相关示例

Note Pad示例程序

参阅

Content Providers

Android为复制和粘贴提供了强大的基于剪贴板的框架。该框架同时支持简单和复杂数据类型,包括文本字符串、复杂数据结构、文本和二进制流数据、甚至程序asset。简单文本数据直接存储于剪贴板内,而复杂数据则保存为一个引用,粘贴应用可利用内容提供器(content provider)进行解析。复制和粘贴可在应用程序内部或多个实现此框架的应用程序之间进行。

因为框架的一部分用到了content provider,本文讨论的内容与Android Content Provider API有些类似,这些API已在Content Provider一章中描述。

 

使用剪贴板框架时,可把数据放入剪辑(clip)对象,然后把该对象放入系统级剪贴板中。clip对象可以是以下三种形式:

Text

文本串。可以直接把字符串放入clip对象,然后把clip对象放入剪贴板中。需要粘贴字符串时,从剪贴板中获取clip对象,然后把字符串拷贝到应用程序的存储中即可。

URI

Uri对象表示任何形式的URI。这主要用于从content provider复制复杂数据。复制数据时,先将Uri对象放入一个clip对象,再把clip对象放入剪贴板中。需要粘贴数据时,先获取clip对象,再获取Uri对象,再把Uri解析到诸如content provider之类的数据源中,然后就能从此数据源中把数据拷贝到应用程序的存储中了。

Intent

一个Intent。这为复制应用程序快捷方式提供了支持。复制数据时,先创建一个Intent并把它放入一个clip对象,再把clip对象放入剪贴板。需要粘贴数据时,可以获取clip 对象并把Intent对象拷贝到应用程序的内存中。

剪贴板同时仅保存一个clip对象。当应用程序把一个clip对象放入剪贴板时,前一个clip对象将会消失。

如果要允许用户把数据粘贴到应用程序中,没必要对所有类型数据都进行处理。在让用户选择粘贴之前,可以先对剪贴板中的数据进行检测。除了包含指定格式的数据之外,clip对象还包含了元数据,它能说明数据是属于哪种格式或MIME类型。此元数据有助于应用程序确定对剪贴板数据执行合适的操作。比如,假定应用程序主要是处理文本信息的,那就可以忽略包含URIIntentclip对象。

还有可能要允许用户只粘贴文本,而不论剪贴板中的数据格式如何。要实现这个目标,可以把剪贴板数据强制转换为文本格式,然后粘贴这些文本。这将在将剪贴板内数据强制转换为文本一节中描述。

 

本节描述类剪贴板框架中所用到的类。

ClipboardManager

Android系统中,系统剪贴板由全局ClipboardManager类表示。此类不需要直接初始化,而是提交getSystemService(CLIPBOARD_SERVICE)来获取一个引用。

 

ClipDataClipData.ItemClipDescription

要把数据加入剪贴板,可以创建一个ClipData对象,它包含了数据描述信息和数据本身。剪贴板每次只保存一个ClipData对象。一个ClipData包含了一个ClipDescription对象和一个以上的ClipData.Item对象。

ClipDescription对象包含了clip相关的元数据信息。特别重要的是,它包含了一个clip数据所对应MIME类型的数组。把clip放入剪贴板后,粘贴应用程序可以利用此数组,程序可以检查此数组以确定其对这些MIME类型的处理能力。

一个ClipData.Item对象包含了文本、URIIntent数据:

Text

一个CharSequence

URI

一个Uri。虽然可以是任何URI值,但通常是包含一个content provider URI。提供数据的应用程序把URI放入剪贴板。需要粘贴数据的应用程序从剪贴板中获取URI,并将它用于访问content provider(或者其它数据源)并取回数据。

Intent

一个Intent。本数据类型允许把应用程序的快捷方式复制到剪贴板中。用户可以在后续的使用中把快捷方式粘贴到其它应用程序中。

可以在一个clip中加入多个ClipData.Item对象。这使得用户可以把多个选中值复制为同一个clip。比如,如果有一个列表widget允许用户一次选择多个选项,就可以把所有选中项一次复制到剪贴板中。要实现这一点,为每个列表项创建一个ClipData.Item,然后把这些ClipData.Item对象加入ClipData对象即可。

 

ClipData常用方法

ClipData类提供了便捷的静态方法来创建一个ClipData对象,附带一个ClipData.Item对象和一个简单的ClipDescription对象作为参数

newPlainText(label, text)

返回包含了单个ClipData.Item对象的ClipData对象,此item对象内含一个文本字符串。ClipDescription对象的标签设置为labelClipDescriptionMIME 类型是MIMETYPE_TEXT_PLAIN

newPlainText()用于创建一个文本字符串clip

newUri(resolver, label, URI)

返回一个包含单个ClipData.ItemClipData对象,此item对象内含一个URIClipDescription对象的标签设置为label。如果URI是一个content类型的URI Uri.getScheme()返回content:),则该方法将用resolverContentResolver对象从content provider中获取可用的MIME类型,并把这些类型保存到ClipDescription中。对于不是content:URI ,该方法把MIME type设置为MIMETYPE_TEXT_URILIST

newUri()用于创建一个URIclip,特别是content: URI

newIntent(label, intent)

返回一个包含单个ClipData.ItemClipData对象,此item对象内含一个IntentClipDescription对象的标签设置为labelMIME类型置为MIMETYPE_TEXT_INTENT

newIntent()用于创建一个Intent对象的clip

 

将剪贴板内数据强制转换为文本

如果应用程序仅需处理文本,可用ClipData.Item.coerceToText()方法转换一下,就可以从剪贴板复制非文本数据。

本方法将把ClipData.Item中的数据转换为文本,并且返回一个CharSequenceClipData.Item.coerceToText()的返回值根据ClipData.Item中的数据格式来确定:

Text

如果ClipData.Item是文本(getText()不为null),则coerceToText()返回文本。

URI

ClipData.Item是个URIgetUri()不为null),则coerceToText()会尝试将其视为content URI

·           如果URI是个content URIprovider能够返回文本流,则coerceToText()返回文本流。

·           如果URI是个content URIprovider无法提供文本流,则coerceToText()返回URI字符串表示形式。该字符串表示形式Uri.toString()的返回值一致。

·           如果URI不是一个content URI,则coerceToText()返回URI字符串表示形式。字符串表示形式Uri.toString()的返回值一致。

Intent

如果ClipData.Item是个IntentgetIntent()不为null),则coerceToText()将其转换为Intent URI后返回。该字符串表示形式与Intent.toUri(URI_INTENT_SCHEME)的返回值一致。

剪贴板的整体框架如图1所示。在复制数据时,应用程序将ClipData对象放入全局的ClipboardManager剪贴板中。ClipData内含了一个或多个ClipData.Item对象,以及一个ClipDescription对象。在粘贴数据时,应用程序先获取ClipData,从ClipDescription中读取MIME类型信息,再从ClipData.Item中或ClipData.Item指向的content provider中读取数据。

A block diagram of the copy and paste framework

1. Android剪贴板框架

 

如前所述,如果要把数据复制到剪贴板(剪贴板句柄指向全局的ClipboardManager对象),需要创建一个ClipData对象,再把一个ClipDescription和一个以上的ClipData.Item对象加入其中,最后把这个ClipData添加到ClipboardManager对象中去。详细情况描述如下:

1.    如果要复制content URI类型的数据,先要建立一个content provider
Note Pad
例程是一个使用content provider复制粘贴数据的示例。NotePadProvider类实现了content providerNotePad类定义了该provider和其它应用程序的交互方式,包括所用的MIME类型。

2.    获取系统剪贴板:

... 

// 如果用户选中复制

case R.id.menu_copy: 

// 获取一个剪贴板服务的句柄

ClipboardManager clipboard =(ClipboardManager) 

getSystemService(Context.CLIPBOARD_SERVICE);

3.    把数据复制到一个新建的ClipData对象:

  • 对于文本

    // 创建一个新的文本clip,用于放入剪贴板中

    ClipData clip =ClipData.newPlainText("simple text","Hello, World!");

  • 对于URI

    以下代码段通过构造了一个URI ,把记录ID编入provider用到的content URI中。更多的技术细节在ID编入URI一节中详述:

    // 根据基本的Uri和联系人姓氏的记录ID,创建一个Uri

    // 声明基本URI字符串

    privatestaticfinalString CONTACTS ="content://com.example.contacts"; 

    // 声明URI的路径字符串,用于复制数据

    privatestaticfinalString COPY_PATH ="/copy"; 

    // 声明需粘帖到剪贴板中的Uri

    Uri copyUri =Uri.parse(CONTACTS + COPY_PATH +"/"+ lastName); 

     ... 

    // 新建一个URI clip对象。系统使用匿名

    // getContentResolver()对象读取provider MIME类型

    // clip对象的标签是"URI",数据是上述创建的Uri

    ClipData clip =ClipData.newUri(getContentResolver(),"URI",copyUri);

     

  • 对于Intent

    以下代码段构造了一个Intent并将其放入clip对象中:

    // 创建Intent 

    Intent appIntent =newIntent(this,com.example.demo.myapplication.class); 

     

    ... 

     

    // 创建一个包含Intentclip对象,标签是"Intent"

    // 数据是上述Intent对象

    ClipData clip =ClipData.newIntent("Intent",appIntent);

4.    把新建的clip对象放入剪贴板:

// 设置剪贴板的主clip. 

clipboard.setPrimaryClip(clip);

 

如上所述,要从剪贴板粘贴数据,需先获得全局剪贴板对象,再获取clip对象,然后查找其中的数据,最后从clip对象中把数据拷贝到自己的存储中。本节详细描述了如何针对三种剪贴板数据的格式进行这些操作。

 

粘贴普通文本

要粘贴普通文本,首先获得全局剪贴板,并确认能否返回普通文本,然后获取clip对象,用getText()把其中文本拷贝到自己的存储中,步骤如下:

1.    getSystemService(CLIPBOARD_SERVICE)获得全局ClipboardManager对象。还要声明一个全局变量来存放粘贴到的文本:

ClipboardManager clipboard =(ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE); 

String pasteData ="";

2.    下一步,确定是否需要启用或禁用当前Activity的“粘贴”选项。还应验证一下剪贴板中是否包含了clip并且程序有能力处理其数据类型:

// 获取“粘贴”菜单项的ID

MenuItem mPasteItem = menu.findItem(R.id.menu_paste);  

// 如果剪贴板中没有数据,则禁用“粘贴”菜单项

// 如果包含数据,确定是否能够处理数据

if(!(clipboard.hasPrimaryClip())){  

    mPasteItem.setEnabled(false);  

    }elseif(!(clipboard.getPrimaryClipDescription().hasMimeType(MIMETYPE_TEXT_PLAIN))){ 

         // 禁用粘贴菜单,因为剪贴板中虽有数据但不是普通文本

        mPasteItem.setEnabled(false); 

    }else{ 

         // 启用粘贴菜单,因为剪贴板中包含普通文本数据

        mPasteItem.setEnabled(true); 

    } 

}

3.    从剪贴板中拷贝数据。仅当“粘贴”菜单项启用时,程序才会运行至此,所以这时可以假定剪贴板已经包含了普通文本。不过还不清楚里面包含了文本字符串还是指向普通文本的URI。以下代码段会进行检测,但只是展示了处理普通文本这部分代码:

// 对用户选中“粘贴”作出响应

case R.id.menu_paste: 

 // 检测剪贴板中的数据项。如果getText()不返回null

// 则表示clip项包含了文本。假定本程序一次仅处理一个数据项

 ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0); 

 // 获取剪贴板中的文本

pasteData = item.getText(); 

 // 如果字符串包含了数据,粘贴操作完成

if(pasteData !=null){ 

    return; 

 // 剪贴板未包含文本。如果包含了URI,则尝试从URI获取数据。

}else{ 

    Uri pasteUri = item.getUri(); 

     // 如果URI包含了数据,则尝试获取文本

    if(pasteUri !=null){ 

         // 调用解析URI并获取数据的过程函数。

        // 此过程函数不在此处展示。

        pasteData = resolveUri(Uri); 

        return; 

    }else{ 

     // 出错。虽然MIME类型是普通文本,但剪贴板所含的不是文本和Uri

    // 报告错误

    Log.e("Clipboard contains an invalid data type"); 

    return; 

    } 

}

 

content URI粘贴数据

如果ClipData.Item对象包含了一个content URI,程序也确认能处理其中的MIME 类型,则可创建一个ContentResolver并调用合适的content provider方法来获取数据。

以下过程描述了如何根据剪贴板中的content URIcontent provider获取数据。程序会先检查MIME类型,确认能够使用该provider提供的数据:

1.    声明全局变量,用于存放MIME类型:

// 声明MIME类型常量,对应provider所提供的MIME类型

publicstaticfinalString MIME_TYPE_CONTACT="vnd.android.cursor.item/vnd.example.contact"

2.    获取全局剪贴板。再创建一个content resolver用于访问content provider

// 获取Clipboard Manager的句柄 

ClipboardManager clipboard =(ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE); 

 // 创建一个content resolver实例

ContentResolver cr = getContentResolver();

3.    从剪贴板获取主clip,并把内容解析为URI:

// 获取剪贴板数据

ClipData clip = clipboard.getPrimaryClip(); 

 if(clip !=null){ 

    // 获取剪贴板的第一项数据

    ClipData.Item item = clip.getItemAt(0); 

    // 试图将数据作为URI读取

    Uri pasteUri = item.getUri();

4.    通过调用getType(Uri)判断URI是否为content URI。如果Uri未指向合法的content provider,该方法返回null

    // 如果剪贴板包含URI引用

    if(pasteUri !=null){ 

        // content URI ? 

        String uriMimeType = cr.getType(pasteUri);

5.    判断content provider是否支持应用程序能够识别的MIME类型。如果支持,则调用ContentResolver.query()来获取数据。返回值是一个Cursor

        // 返回值不为null,表示Uricontent Uri 

        if(uriMimeType !=null){ 

            // content provider提供的MIME类型当前程序是否可用?

            if(uriMimeType.equals(MIME_TYPE_CONTACT)){ 

                // 获取content provider数据

                Cursor pasteCursor = cr.query(uri,null,null,null,null); 

                // 如果Cursor包含数据,则移至第一条记录

                if(pasteCursor !=null){ 

                    if(pasteCursor.moveToFirst()){ 

                    // 获取Cursor数据。

                    // 代码根据数据格式不同而有所变化

                    } 

                } 

                // 关闭Cursor 

                pasteCursor.close(); 

             } 

         } 

     } 

}

 

粘贴Intent

要粘贴一个意图Intent,首先获取全局剪贴板,再检查ClipData.Item对象是否包含Intent。然后调用getIntent()来把Intent拷贝到程序的存储中。以下代码段演示了这一过程:

// 获取Clipboard Manager句柄 

ClipboardManager clipboard =(ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE); 

// 通过判断getIntent()是否为null 检查clip item是否包含Intent

Intent pasteIntent = clipboard.getPrimaryClip().getItemAt(0).getIntent(); 

if(pasteIntent !=null){ 

    // 处理Intent 

}else{ 

    // 忽略剪贴板内容;

    // 假如程序认为剪贴板应该包含Intent,可在此报告错误

}

 

利用Content Provider复制复杂数据

Content provider支持对复杂数据的复制,比如数据库记录或文件流之类。在复制数据时,把一个content URI放入剪贴板中。然后粘贴应用程序从剪贴板中获取此URI,并用它读取数据库数据或者文件流的描述符。

由于粘贴应用程序只是将content URI作为数据读取,因此还需要知道应获取数据的哪些部分。可以把所需数据的ID编入URI本身,或者让URI只精确返回所需复制部分的数据。采用哪种方式取决于数据是如何组织在一起的。

以下章节描述了如何创建URI、如何提供复杂数据、如何提供文件流。以下假定开发人员已经熟悉了content provider的一般设计规则。

 

ID置入URI编码

利用URI把数据复制到剪贴板时,有一项实用技术就是把数据的ID置入URI编码本身。然后content provider可以从URI得到ID,并用ID来读取数据。粘贴应用程序不必知道ID是否存在,要做的所有操作就是从剪贴板获取“引用”(URIID),并把它交给content provider,然后读取数据。

通常的编码方式是把ID附在content URI后面。比如,假定已定义provider URI如下:

"content://com.example.contacts"

如果需要把名称置入URI,应该使用如下代码:

String uriString ="content://com.example.contacts"+"/"+"Smith" 

// 现在uriString包含了content://com.example.contacts/Smith 

// 根据字符串变量创建uri对象

Uri copyUri =Uri.parse(uriString);

如果程序中已经用到了content provider,只需新增一个指示复制数据的URI路径。比如,假设已存在以下URI路径:

"content://com.example.contacts"/people 

"content://com.example.contacts"/people/detail 

"content://com.example.contacts"/people/images

下面加入一个用于复制的URI

"content://com.example.contacts/copying"

可以利用模式匹配来检测到"copy" URI,并用代码进行复制和粘贴处理。

如果是用content provider、内部数据库、内部表来组织数据,通常即可使用以上编码技术。这种情况下会有多块数据需要复制,很可能每块数据都会有一个唯一ID当粘贴应用程序查询时,可以用此ID查找并返回数据。

如果没有多块数据需要复制,可能就不必把ID进行编码。可以简单地使用能够唯一标识providerURI即可。查询时,provider将会返回它包含的数据。

Note Pad示例程序中就用ID获取了单条记录,以便从note列表中打开一条note。此示例使用了SQL数据库中的_id字段,不过可以根据需要使用任何数字或字符ID

 

复制数据结构

为了复制和粘贴复杂数据,应该创建一个content provider,它是ContentProvider组件的子类。还应该将编码后的URI放入剪贴板,此URI指向了需提供的正确记录。此外,还必须考虑应用程序的现状:

·       如果已有一个content provider,可以增加它的功能。可能只需要修改query()方法,使得它能处理粘贴程序所需的URI即可。有可能要修改方法来对URI中的“copy”进行模式匹配。

·       如果应用程序拥有内部数据库,可能需要将此数据库移入content provider,便于从中拷贝数据。

·       如果目前没有用到数据库,可以实现一个简单的content provider,它的唯一用途就是为程序提供粘贴自剪贴板的数据。

content provider中,至少会需要覆盖以下方法:

query()

粘贴应用程序将会假定,通过此方法能够获取剪贴板中URI指定的数据。为了支持复制功能,应该在本方法中对包含指定“复制”路径的URI进行检测。然后,程序可以创建一个“复制”URI并放入剪贴板中,此URI包含了复制路径和指向实际复制记录的指针。

getType()

本方法应该返回MIME类型或者需复制数据的类型。为了把MIME类型放入新建的ClipData对象,newUri()方法将会调用getType()

复杂数据的MIME类型在Content Providers一节中描述。

注意,其它的content provider方法是没必要用到的,比如insert()update()。粘贴应用程序只需要获取所用的MIME类型并从provider拷贝数据。如果已经实现了这些方法,那它们也不会影响复制操作。

以下代码段演示了如何建立复制复杂数据的应用程序:

1.    声明全局常量,定义基本URI字符串和路径,用于指明复制数据的URI字符串。同时声明需复制数据的MIME类型:

// 声明基本URI字符串

privatestaticfinalString CONTACTS ="content://com.example.contacts"; 

// 声明用于复制数据的URI路径字符串

privatestaticfinalString COPY_PATH ="/copy"; 

 

// 声明需复制数据的MIME类型

publicstaticfinalString MIME_TYPE_CONTACT="vnd.android.cursor.item/vnd.example.contact"

2.    用户复制数据的Activity中,创建把数据复制到剪贴板的代码。在响应复制请求时,将URI放入剪贴板中:

publicclassMyCopyActivityextendsActivity{ 

    ... 

// 用户已经选中了姓名并请求复制

case<="" span="">.id.menu_copy: 

    // 在基本URI后附加姓名

    // 姓名存于"lastName" 

    uriString = CONTACTS + COPY_PATH +"/"+ lastName;<="" span="">

    // 字符串编码为URI 

    Uri copyUri =Uri.parse(uriString);;     // 获取剪贴板服务的句柄

    ClipboardManager clipboard d =(ClipboardManager) 

        getSystemService(Context.CLIPBOARD_SERVICE););    ClipData clip=ClipData.newUri(getContentResolver(),"URI", copyUri););    // / 设置剪贴板的主clip.    clipboard.setPrimaryClip(clip););

3.    content provider的全局部分(global scope),创建一个URI匹配器,并加入与剪贴板URI相匹配的URI模式。

publicclassMyCopyProviderextendsContentProvider{>{    .....// Uriri匹配器对象,用于简化对content URI模式匹配操作。

privatestaticfinalUriMatcher sURIMatcher=newUriMatcher(UriMatcher.NO_MATCH););// 整数,用于URI模式的开关变量。

privatestaticfinalint GET_SINGLE_CONTACT =>=0;.....// content URI加入匹配器。

// 匹配"content://com.example.contacts/copy/*" 

sUriMatcher.addURI(CONTACTS,"names/*", GET_SINGLE_CONTACT);

4.    建立query()方法。在本方法中可用不同的代码处理各种URI模式,不过下面仅列出了剪贴板复制操作所用到的模式:

// 建立providerquery()方法

publicCursor query(Uri uri,String[] projection,String selection,String[]selectionArgs, 

    String sortOrder){ 

    ... 

    // 基于传入的content URI进行分支 

    switch(sUriMatcher.match(uri)){ 

    case GET_SINGLE_CONTACT: 

        // 根据请求的姓名查询并返回contact

        // 在此应对传入的URI解码,基于姓名查询数据并返回结果Cursor

    ... 

}

5.    建立getType()方法,返回合适的返回数据MIME类型:

// 建立providergetType()方法

publicString getType(Uri uri){ 

 

    ...

    switch(sUriMatcher.match(uri)))){ 

    GET_SINGLE_CONTACT: 

            return(MIME_TYPE_CONTACT););

content URI粘贴数据一节描述了如何从剪贴板获取content URI,并用它读取并粘贴数据。

 

复制数据流

可以将大量的文本和二进制数据以流的形式进行复制和粘贴。数据可以具有如下格式:

·       保存在物理设备上的文件。

·       来自socket的流。

·       保存在provider底层数据库系统中的大量数据。

数据流content provider用文件描述符对象而不是Cursor< span="">AssetFileDescriptor。粘贴应用程序利用此文件描述符来读取数据流。流。

要建立用provider复制数据流的应用程序,请按以下步骤进行:

1.    为放入剪贴板的数据流建立content URI。可有以下选择:

o                将数据流的ID编入URI,如上ID编入URI所述,然后在provider中保存一张表,其中包含了ID和相关的流名称。

o                将流名称直接编入URI

o                用唯一的URI,总是从provider返回当前流。如果选用此项,则每次通过URI把流复制到剪贴板时,必须记得更新provider,使它指向新的流。

2.    为每类提供的数据流指定一个MIME类型。粘贴应用程序需要此信息来确定能否粘贴剪贴板中的数据。

3.    实现ContentProvider中的一个方法,返回流的文件描述符。如果ID已编入content URI,则用此方法来确定需要打开的流。

4.    把数据复制到剪贴板时,构造content URI并放入剪贴板中。

要粘贴数据流时,应用程序先从剪贴板获取clip,读取URI,然后调用ContentResolver文件描述符方法打开流。ContentResolver方法将调用相应的ContentProvider方法,把content URI传入其中。provider把文件描述符返回给ContentResolver方法。这时粘贴程序就能读取流中的数据了。

以下列表展示了对content provider而言最重要的文件描述符方法。每个方法都有后缀名为“Descriptor< span="">ContentResolver方法与之相对应。比如,模拟openAssetFile()ContentResolveropenAssetFileDescriptor()

openTypedAssetFile()
仅当给出的MIME类型能被provider支持时,本方法返回一个asset文件描述符。调用方(执行粘贴的应用)提供MIME类型模式。如果能提供此类型MIME的话,content provider(把URI复制到剪贴板的应用)将返回一个AssetFileDescriptor文件句柄,不能提供则抛出异常。常。
本方法用于处理文件的片段,可以用它读取content provider拷入剪贴板的asset

openAssetFile()
本方法是比openTypedAssetFile()更通用的方法。它不对支持的MIME类型进行判断过滤,但可用于读取文件的片段。

openFile()
这是比openAssetFile()更加通用的格式。它不能读取文件片段。

可以选用openPipeHelper()方法作为文件描述符方法,这让粘贴应用可以用管道在后台读取流数据。使用此方法需要实现ContentProvider.PipeDataWriter接口。在Note Pad示例程序中有相关例程,位于NotePadProvider.java中的openTypedAssetFile()方法。

 

要为应用程序设计高效的复制与粘贴功能,请记住以下几点:

·       任何时候,剪贴板中都只有一个clip。系统中任何应用程序执行了新的复制操作,都会覆盖之前的clip 。由于用户可能会跳离应用程序,并在返回前执行了复制,因此不能假定剪贴板中包含了前一次在此程序中复制的内容。

·       设计clip< span="">ClipData.Item对象的初衷,是为了支持一次复制和粘贴多个选项,而不是为了单个选项能包含多种不同的格式。通常一个clip中的所有ClipData.Item对象都应该具有相同的格式,也就是说,它们应该全都是简单文本、或者或者content URI、或者Intent,而不能混在一起使用。

·       提供数据时,可以提交各种不同的MIME描述。把所支持的MIME< span="">ClipDescription,然后在content provider中实现这些MIME类型。

·       从剪贴板读取数据时,应用程序有责任对可用的MIME类型进行检查,然后决定要使用哪些类型。即使剪贴板中存在clip,而用户也请求了粘贴,应用程序也不一定要执行粘贴。应该MIME类型能够兼容时才执行粘贴。可以选用coerceToText()把剪贴板数据强制转换成文本。如果应用程序能支持更多可用的用的MIME类型,可以让用户先选择其中一个再使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值