Android Developer:android
在開發一些系統應用的時候,咱們會用到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.Itemapp
粘貼數據ide
爲了獲取剪貼板中的數據,應用程序必須正確解析數據;若是CipData.Item包含的信息爲文本或者Intent類型,有一點須要說明:文本只能解析爲文本,intent一般用來當中快捷方式或者其餘的動做類型;若是你只是想獲取文本內容,你能夠經過Item.coerceToText()方法強制獲取,這樣就不須要考慮MIME類型,應爲全部的item都會被強制轉換爲文本。oop
複雜的數據類型一般用URL來完成粘貼。容許接受者以URI方式從ContentProvider的獲取數據。剪貼時須要填寫正確的MIME類型; 如:newUri(ContentResolver,CharSequence,URI)這樣才能被正確的處理。post
下面是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以流的方式處理數據。ui
以下面是Item.coerceToText的實現:this
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;
轉 :http://wenzhutech.diandian.com/post/2012-06-07/40028957456