zoukankan      html  css  js  c++  java
  • Android应用开发之(通过ClipboardManager, ClipData进行复制粘贴)

    在开发一些系统应用的时候,我们会用到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.
     */
    @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;

  • 相关阅读:
    Windows Azure Storage (17) Azure Storage读取访问地域冗余(Read Access – Geo Redundant Storage, RA-GRS)
    SQL Azure (15) SQL Azure 新的规格
    Azure China (5) 管理Azure China Powershell
    Azure China (4) 管理Azure China Storage Account
    Azure China (3) 使用Visual Studio 2013证书发布Cloud Service至Azure China
    Azure China (2) Azure China管理界面初探
    Azure China (1) Azure公有云落地中国
    SQL Azure (14) 将云端SQL Azure中的数据库备份到本地SQL Server
    [New Portal]Windows Azure Virtual Machine (23) 使用Storage Space,提高Virtual Machine磁盘的IOPS
    Android数据库升级、降级、创建(onCreate() onUpgrade() onDowngrade())的注意点
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/4808960.html
Copyright © 2011-2022 走看看