Android应用开发之(通过ClipboardManager, ClipData进行复制粘贴)
在開發(fā)一些系統(tǒng)應(yīng)用的時(shí)候,我們會用到Android的剪貼板功能,比如將文本文件、或者其他格式的內(nèi)容復(fù)制到剪貼板或者從剪貼板獲取數(shù)據(jù)等操作。Android平臺中每個(gè)常規(guī)的應(yīng)用運(yùn)行在自己的進(jìn)程空間中,相對于Win32而言Android上之間的進(jìn)程間傳遞主要有IPC、剪切板。當(dāng)然今天我們說下最簡單的ClipboardManager。使用剪切板可以直接實(shí)現(xiàn)數(shù)據(jù)的傳輸。整個(gè)實(shí)現(xiàn)比較簡單,注意剪切板中的類型判斷。
使用起來很簡單,系統(tǒng)給我們提供了很方便的接口,如下文本信息復(fù)制如下所示:
//獲取剪貼板管理服務(wù) ClipboardManager cm =(ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); //將文本數(shù)據(jù)復(fù)制到剪貼板 cm.setText(message); //讀取剪貼板數(shù)據(jù) 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代表剪貼板中剪切數(shù)據(jù)。它有一個(gè)或多個(gè)Item實(shí)例,每個(gè)可容納一個(gè)或多個(gè)數(shù)據(jù)項(xiàng)。 ClipData包含ClipDescription,用來描述剪貼內(nèi)容的重要元數(shù)據(jù)。尤其是getDescription().getMimeType(INT)必須返回正確的MIME類型。為了正確的設(shè)置剪貼內(nèi)容的MIME類型,建議使用newPlainText(CharSequence,CharSequence的),newUri(ContentResolver,CharSequence中,URI),newIntent(CharSequence, Intent)構(gòu)造ClipData。每個(gè)Item的實(shí)例可以是三大數(shù)據(jù)類型之一:text,intent,URI。詳情請參閱ClipData.Item
粘貼數(shù)據(jù)
為了獲取剪貼板中的數(shù)據(jù),應(yīng)用程序必須正確解析數(shù)據(jù);如果CipData.Item包含的信息為文本或者Intent類型,有一點(diǎn)需要說明:文本只能解析為文本,intent通常用來當(dāng)中快捷方式或者其他的動(dòng)作類型;如果你只是想獲取文本內(nèi)容,你可以通過Item.coerceToText()方法強(qiáng)制獲取,這樣就不需要考慮MIME類型,應(yīng)為所有的item都會被強(qiáng)制轉(zhuǎn)換為文本。
復(fù)雜的數(shù)據(jù)類型通常用URL來完成粘貼。允許接受者以URI方式從ContentProvider的獲取數(shù)據(jù)。剪貼時(shí)需要填寫正確的MIME類型; 如:newUri(ContentResolver,CharSequence,URI)這樣才能被正確的處理。
下面是NotePad應(yīng)用粘貼的例子。當(dāng)從剪貼板中接受數(shù)據(jù)時(shí),如果剪貼板中包含已有note的URI引用時(shí),根據(jù)URI復(fù)制其結(jié)構(gòu)到新的Note中,否則通過根據(jù)獲取的文本內(nèi)容作為新的筆記內(nèi)容:
/*** 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 ManagerClipboardManager clipboard = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);// Gets a content resolver instanceContentResolver cr = getContentResolver();// Gets the clipboard data from the clipboardClipData clip = clipboard.getPrimaryClip();if (clip != null) {String text=null;String title=null;// Gets the first item from the clipboard dataClipData.Item item = clip.getItemAt(0);// Tries to get the item's contents as a URI pointing to a noteUri 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 providerPROJECTION, // Get the columns referred to in the projectionnull, // No selection variablesnull, // No selection variables, so no criteria are needednull // 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);} }?
很多應(yīng)用可以處理多種類型的數(shù)據(jù),例如:E_mail應(yīng)用希望用戶粘貼圖片或者其他二進(jìn)制文件作為附件。這就需要通過ContentResolver的getStreamTypes(Uri, String)和openTypedAssetFileDescriptor(Uri,String,android.os.Bundle)方法處理。這需要客戶端檢測一個(gè)特定的內(nèi)容URI以流的方式處理數(shù)據(jù)。
如下面是Item.coerceToText的實(shí)現(xiàn):
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 ""; }?
復(fù)制數(shù)據(jù)
做為復(fù)制的源數(shù)據(jù),應(yīng)用要構(gòu)造容易被接受解析的剪貼數(shù)據(jù)。如果要復(fù)制包含文本,Intent,或者URI,簡單的方式是使用ClipData.Item包含相應(yīng)的類型數(shù)據(jù);
復(fù)雜的數(shù)據(jù)類型要求支持以ContentProvide方式描述和生成被接受的數(shù)據(jù),常用的解決方案是以URI的方式復(fù)制數(shù)據(jù),URI有復(fù)雜結(jié)構(gòu)的數(shù)據(jù)組成,只有理解這種結(jié)果的應(yīng)用才能接受處理這樣的數(shù)據(jù);
對于不具有內(nèi)在的數(shù)據(jù)結(jié)構(gòu)知識的應(yīng)用,可使用任意可接受的數(shù)據(jù)流類型。這是通過實(shí)現(xiàn)ContentProvider的getStreamTypes(URI,String)和openTypedAssetFile(URI字符串,android.os.Bundle)方法進(jìn)行獲取。
回到記事本應(yīng)用程序的例子,它是將要復(fù)制的內(nèi)容以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/plaincase 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 supportedif (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 noteREAD_NOTE_PROJECTION, // Gets a projection containing the note's ID, title,// and contentsnull, // No WHERE clause, get all matching recordsnull, // Since there is no WHERE clause, no selection criterianull // Use the default sort order (modification date,// descending);// If the query fails or the cursor is empty, stopif (c == null || !c.moveToFirst()) {// If the cursor is empty, simply close the cursor and returnif (c != null) {c.close();}// If the cursor is null, throw an exceptionthrow 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復(fù)制操作現(xiàn)在只是簡單的構(gòu)造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 itselfclipboard.setPrimaryClip(ClipData.newUri( // new clipboard item holding a URIgetContentResolver(), // resolver to retrieve URI info"Note", // label for the clipnoteUri) // the URI);// Returns to the caller and skips further processing.return true;?
注 如果粘貼操作需要文本(例如粘貼到編程器中)coerceToText(Context)方式會通知內(nèi)容提供者將URI轉(zhuǎn)換為URL;
轉(zhuǎn)載于:https://www.cnblogs.com/Free-Thinker/p/4808960.html
總結(jié)
以上是生活随笔為你收集整理的Android应用开发之(通过ClipboardManager, ClipData进行复制粘贴)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑开机出现无法启动怎么回事啊 电脑开不
- 下一篇: Android笔记(三十一)Androi