public class ClipData
extends Object
implements Parcelable
java.lang.Object | |
↳ | android.content.ClipData |
在剪贴板上表示剪切的数据。
ClipData是一个复杂的类型,包含一个或多个Item实例,每个实例可以包含一个或多个数据项表示。 为了向用户显示,它也有一个标签。
一个ClipData包含一个ClipDescription
,它描述了关于剪辑的重要元数据。 特别是,其getDescription().getMimeType(int)
必须返回描述剪辑中数据的正确MIME类型。 对于正确构建一个剪辑正确的MIME类型的帮助下,使用newPlainText(CharSequence, CharSequence)
, newUri(ContentResolver, CharSequence, Uri)
,并newIntent(CharSequence, Intent)
。
每个Item实例可以是三个主要类型的数据之一:简单的CharSequence文本,单个Intent对象或Uri。 详情请参阅ClipData.Item
。
有关使用剪贴板框架的更多信息,请阅读 Copy and Paste开发人员指南。
要实现将ClipData对象粘贴或拖放到应用程序中,应用程序必须正确解释数据的用途。 如果它包含的是ClipData.Item
是简单文本或意图,则几乎不需要做:文本只能被解释为文本,而Intent通常用于创建快捷方式(例如在主屏幕上放置图标)或其他操作。
如果你想要的只是剪辑数据的文本表示,你可以使用便捷方法Item.coerceToText
。 在这种情况下,通常不需要担心由getDescription().getMimeType(int)
报告的MIME类型,因为任何剪辑项目总是可以转换为字符串。
更复杂的交换将通过URI完成,特别是“content:”URI。 内容URI允许ClipData项目的接收者与持有数据的ContentProvider紧密交互,以便协商数据的传输。 剪辑还必须填入可用的MIME类型; newUri(ContentResolver, CharSequence, Uri)
会照顾正确地做到这一点。
例如,下面是一个简单的NotePad应用程序的粘贴功能。 从剪贴板中检索数据时,它可以做两件事情:如果剪贴板包含对现有笔记的URI引用,则会将笔记的整个结构复制到新笔记中; 否则,它只是将剪辑强制转换为文本并将其用作新注释的内容。
/** * 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); } }
在很多情况下,应用程序可以粘贴各种类型的数据流。 例如,电子邮件应用程序可能希望允许用户将图像或其他二进制数据粘贴为附件。 这是通过ContentResolver getStreamTypes(Uri, String)
和openTypedAssetFileDescriptor(Uri, String, android.os.Bundle)
方法完成的。 这些允许客户端发现特定内容URI可以作为流提供的数据类型并检索数据流。
例如, Item.coerceToText
本身的实现使用它来尝试将URI剪辑作为文本流进行检索:
public CharSequence coerceToText(Context context) { // If this Item has an explicit textual value, simply return that. CharSequence text = getText(); if (text != null) { return text; } // If this Item has a URI value, try using that. Uri uri = getUri(); if (uri != 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(uri, "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("ClipData", "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 uri.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. Intent intent = getIntent(); if (intent != null) { return intent.toUri(Intent.URI_INTENT_SCHEME); } // Shouldn't get here, but just in case... return ""; }
要成为剪辑的来源,应用程序必须构建一个ClipData对象,任何收件人都可以为其上下文进行最佳解释。 如果剪辑要包含简单的文本,Intent或URI,则很容易:可以构建并使用包含适当数据类型的ClipData.Item
。
更复杂的数据类型需要在ContentProvider中实现支持来描述和生成收件人的数据。 一种常见的情况是,应用程序在剪贴板上放置用户已复制的对象的内容:URI,该URI中的数据由复杂的结构组成,只有其他直接了解该结构的应用程序才能使用该结构。
对于不具备数据结构固有知识的应用程序,持有该数据结构的内容提供者可以将数据作为任意数量的类型的数据流提供。 这是通过实施ContentProvider getStreamTypes(Uri, String)
和openTypedAssetFile(Uri, String, android.os.Bundle)
方法完成的。
回到我们简单的NotePad应用程序,这是它可能必须将单个音符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) { } } }
我们的NotePad应用程序中的复制操作现在只是制作一个包含被复制音符的URI的剪辑的简单问题:
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作为文本并成功粘贴整个笔记。
Nested classes |
|
---|---|
class |
ClipData.Item ClipData中单个项目的描述。 |
Inherited constants |
---|
From interface android.os.Parcelable
|
Fields |
|
---|---|
public static final Creator<ClipData> |
CREATOR |
Public constructors |
|
---|---|
ClipData(CharSequence label, String[] mimeTypes, ClipData.Item item) 创建一个新的剪辑。 |
|
ClipData(ClipDescription description, ClipData.Item item) 创建一个新的剪辑。 |
|
ClipData(ClipData other) 创建一个新剪辑,该剪辑是另一个剪辑的副本。 |
Public methods |
|
---|---|
void |
addItem(ClipData.Item item) 将新项目添加到整个ClipData容器。 |
int |
describeContents() 描述此Parcelable实例的封送表示中包含的特殊对象的种类。 |
ClipDescription |
getDescription() 返回与此数据关联的 |
ClipData.Item |
getItemAt(int index) 在剪辑数据中返回单个项目。 |
int |
getItemCount() 返回剪辑数据中的项目数量。 |
static ClipData |
newHtmlText(CharSequence label, CharSequence text, String htmlText) 创建一个新的ClipData保存类型为 |
static ClipData |
newIntent(CharSequence label, Intent intent) 创建一个新的ClipData,其中包含一个MIME类型为 |
static ClipData |
newPlainText(CharSequence label, CharSequence text) 创建一个新的ClipData保存类型为 |
static ClipData |
newRawUri(CharSequence label, Uri uri) 创建一个新的ClipData,它包含一个MIME类型为 |
static ClipData |
newUri(ContentResolver resolver, CharSequence label, Uri uri) 创建一个包含URI的新ClipData。 |
String |
toString() 返回对象的字符串表示形式。 |
void |
writeToParcel(Parcel dest, int flags) 将此对象平铺到一个包裹中。 |
Inherited methods |
|
---|---|
From class java.lang.Object
|
|
From interface android.os.Parcelable
|
ClipData (CharSequence label, String[] mimeTypes, ClipData.Item item)
创建一个新的剪辑。
Parameters | |
---|---|
label |
CharSequence : Label to show to the user describing this clip. |
mimeTypes |
String : An array of MIME types this data is available as. |
item |
ClipData.Item : The contents of the first item in the clip. |
ClipData (ClipDescription description, ClipData.Item item)
创建一个新的剪辑。
Parameters | |
---|---|
description |
ClipDescription : The ClipDescription describing the clip contents. |
item |
ClipData.Item : The contents of the first item in the clip. |
ClipData (ClipData other)
创建一个新剪辑,该剪辑是另一个剪辑的副本。 这会对剪辑中的所有项目进行深层复制。
Parameters | |
---|---|
other |
ClipData : The existing ClipData that is to be copied. |
void addItem (ClipData.Item item)
将新项目添加到整个ClipData容器。
此方法不会更新ClipDescription
中可用MIME类型的ClipDescription
。 只有在添加不向该剪辑添加新MIME类型的项目时才应使用它。 如果不是这种情况,应使用ClipData(CharSequence, String[], Item)
以及MIME类型的完整列表。
Parameters | |
---|---|
item |
ClipData.Item : Item to be added. |
int describeContents ()
描述此Parcelable实例的封送表示中包含的特殊对象的种类。 例如,如果对象将在writeToParcel(Parcel, int)
的输出中包含writeToParcel(Parcel, int)
,则此方法的返回值必须包含CONTENTS_FILE_DESCRIPTOR
位。
Returns | |
---|---|
int |
a bitmask indicating the set of special object types marshaled by this Parcelable object instance. |
ClipDescription getDescription ()
返回与此数据关联的 ClipDescription
,描述它包含的内容。
Returns | |
---|---|
ClipDescription |
ClipData.Item getItemAt (int index)
在剪辑数据中返回单个项目。 索引的范围可以从0到getItemCount()
-1。
Parameters | |
---|---|
index |
int
|
Returns | |
---|---|
ClipData.Item |
ClipData newHtmlText (CharSequence label, CharSequence text, String htmlText)
创建一个新的ClipData保存类型为 MIMETYPE_TEXT_HTML
数据。
Parameters | |
---|---|
label |
CharSequence : User-visible label for the clip data. |
text |
CharSequence : The text of clip as plain text, for receivers that don't handle HTML. This is required. |
htmlText |
String : The actual HTML text in the clip. |
Returns | |
---|---|
ClipData |
Returns a new ClipData containing the specified data. |
ClipData newIntent (CharSequence label, Intent intent)
创建一个新的ClipData,其中包含一个MIME类型为 MIMETYPE_TEXT_INTENT
的Intent。
Parameters | |
---|---|
label |
CharSequence : User-visible label for the clip data. |
intent |
Intent : The actual Intent in the clip. |
Returns | |
---|---|
ClipData |
Returns a new ClipData containing the specified data. |
ClipData newPlainText (CharSequence label, CharSequence text)
创建一个新的ClipData保存类型为 MIMETYPE_TEXT_PLAIN
数据。
Parameters | |
---|---|
label |
CharSequence : User-visible label for the clip data. |
text |
CharSequence : The actual text in the clip. |
Returns | |
---|---|
ClipData |
Returns a new ClipData containing the specified data. |
ClipData newRawUri (CharSequence label, Uri uri)
创建一个新的ClipData,它包含一个MIME类型为MIMETYPE_TEXT_URILIST
的URI。 与newUri(ContentResolver, CharSequence, Uri)
不同,没有任何关于URI的推断 - 如果它是一个持有位图的content:URI,则报告的类型仍然是uri-list。 小心使用这个!
Parameters | |
---|---|
label |
CharSequence : User-visible label for the clip data. |
uri |
Uri : The URI in the clip. |
Returns | |
---|---|
ClipData |
Returns a new ClipData containing the specified data. |
ClipData newUri (ContentResolver resolver, CharSequence label, Uri uri)
创建一个包含URI的新ClipData。 如果URI是内容:URI,则会向内容提供者查询其数据的MIME类型并将其用作MIME类型。 否则,它将使用MIME类型MIMETYPE_TEXT_URILIST
。
Parameters | |
---|---|
resolver |
ContentResolver : ContentResolver used to get information about the URI. |
label |
CharSequence : User-visible label for the clip data. |
uri |
Uri : The URI in the clip. |
Returns | |
---|---|
ClipData |
Returns a new ClipData containing the specified data. |
String toString ()
返回对象的字符串表示形式。 一般来说, toString
方法返回一个“文本表示”该对象的字符串。 结果应该是一个简洁但内容丰富的表述,对于一个人来说很容易阅读。 建议所有子类重写此方法。
类Object
的toString
方法返回一个字符串,其中包含对象为实例的类的名称,符号字符“ @
”以及对象的哈希代码的无符号十六进制表示形式。 换句话说,这个方法返回一个字符串,其值等于:
getClass().getName() + '@' + Integer.toHexString(hashCode())
Returns | |
---|---|
String |
a string representation of the object. |
void writeToParcel (Parcel dest, int flags)
将此对象平铺到一个包裹中。
Parameters | |
---|---|
dest |
Parcel : The Parcel in which the object should be written. |
flags |
int : Additional flags about how the object should be written. May be 0 or PARCELABLE_WRITE_RETURN_VALUE . |