Android應用開發之(通過ClipboardManager, ClipData進行複製粘貼)

來源:互聯網
上載者:User

http://iandroiddev.com/post/2012-06-06/40028637105

在開發一些系統應用的時候,我們會用到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.Item

粘貼資料

為了擷取剪貼簿中的資料,應用程式必須正確解析資料;如果CipData.Item包含的資訊為文本或者Intent類型,有一點需要說明:文本只能解析為文本,intent通常用來當中捷徑或者其他的動作類型;如果你只是想擷取常值內容,你可以通過Item.coerceToText()方法強制擷取,這樣就不需要考慮MIME類型,應為所有的item都會被強制轉換為文本。

複雜的資料類型通常用URL來完成粘貼。允許接受者以URI方式從ContentProvider的擷取資料。剪貼時需要填寫正確的MIME類型; 如:newUri(ContentResolver,CharSequence,URI)這樣才能被正確的處理。

下面是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以流的方式處理資料。

如下面是Item.coerceToText的實現:

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. */@Overridepublic 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. */@Overridepublic 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. */@Overridepublic 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;

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.