转自:https://github.com/MyLifeMyTravel/AndroidDemo Android提供了一个强大的剪贴板框架,用于复制和粘贴。它支持文本、二进制数据流或其它复杂的数据。 Android 剪贴板框架如图: 从图中可以看出,Android 剪贴板框架主要涉及到ClipboardManager,ClipData,ClipData.item,ClipDescription四个类。 这四个类的简介如下: 1.ClipboardManager是系统全局的剪切板对象,通过context.getSystemService(CLIPBOARD_SERVICE)获得。 2.ClipData,即clip对象,在系统剪切板中只能存在一个,当另一个clip对象进来时,前一个自动销毁。 3.ClipData.item,即data item,它可以包含文本,Uri,或intent数据,一个clip对象可以包括一个或多个item对象。通过addItem(ClipData.Item item)可以实现在clip对象中添加item。 >文本:直接放在clip对象中,然后放在剪切板里,粘贴文本时直接从剪切板里拿到clip对象,把字符串 放入应用存储中。 >Uri:对于复杂数据的剪贴拷贝并不是直接将数据放入内存,而是通过uri来实现,通过uri定位手机上的 资源,从而实现拷贝。 >intent:复制的时候intent后被直接放入clip对象中,相当于拷贝了一个快捷方式。 4.ClipDescription:即clip metadata,它包括了ClipData对象的metadata信息。可以通过getMimeType(int index)获取,一般index=0.MimeType一般有以下四种类型:

// 对应 ClipData newPlainText(label, text) 的 MimeType
public static final String MIMETYPE_TEXT_PLAIN = "text/plain";
// 对应 ClipData.newHtmlText(label, text, htmlText) 的 MimeType
public static final String MIMETYPE_TEXT_HTML = "text/html";
// 对应 ClipData.newUri(cr, label, uri) 的 MimeType
public static final String MIMETYPE_TEXT_URILIST = "text/uri-list";
// 对应 ClipData.newIntent(label, intent) 的 MimeType
public static final String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent";

但MIMETYPE_TEXT_URILIST有点特殊,当Uri为content://uri时,她会转为具体的MimeType,后面有例子。

剪贴板的简单使用

以拷贝文本为例,剪贴板的使用可以分为以下几步:

//1.获得ClipboardManager
		ClipboardManager clipboardManager=(ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);
//2.将数据放到clip对象中 
        ClipData clipData=ClipData.newPlainText("textCopy",getResources().getString(R.string.source));
							// 类似的方法还有
							//创建一个包含 htmlText 的 ClipData
							//一般在浏览器中对网页进行拷贝的时候会调用此方法
							//其中 htmlText 是包含 HTML 标签的字符串
							//static public ClipData newHtmlText(CharSequence label, CharSequence text, String htmlText);
							//创建一个包含 Intent 的 ClipData
							//static public ClipData newIntent(CharSequence label, Intent intent);
							//创建一个包含 Uri 的 ClipData,MimeType 会根据 Uri 进行修改
							//static public ClipData newUri(ContentResolver resolver, CharSequence label, Uri uri);
							//与 newUri 相对应,但是并不会根据 Uri 修改 MimeType
							//static public ClipData newRawUri(CharSequence label, Uri uri);
//3.将clipdata放入剪切板中
		 clipboardManager.setPrimaryClip(clipData);
//4.从剪切板中取出数据
        if(clipboardManager.hasPrimaryClip()){
            ClipData clipData1=clipboardManager.getPrimaryClip();
            ClipDescription description=clipboardManager.getPrimaryClipDescription();
            String label= (String) description.getLabel();
            String text=clipData.getItemAt(0).getText().toString();
            tv.setText(text);
        }

其他数据的拷贝参考: https://www.jianshu.com/p/213d7062cdbe

对于剪贴板大部分操作都封装在 ClipboardUtil.java 里,使用时请记录调用 init(Context context) 方法进行初始化,建议在 Application.onCreate() 中进行,否则会造成内存泄漏。 /**

  • 剪贴板工具类
  • http://developer.android.com/guide/topics/text/copy-paste.html
  • Created by littlejie on 2016/4/15. */
public class ClipboardUtil {

   public static final String TAG = ClipboardUtil.class.getSimpleName();

   private static final String MIME_CONTACT = "vnd.android.cursor.dir/person";
   /**
    * 由于系统剪贴板在某些情况下会多次调用,但调用间隔基本不会超过5ms
    * 考虑到用户操作,将阈值设为100ms,过滤掉前几次无效回调
    */
   private static final int THRESHOLD = 100;

   private Context mContext;
   private static ClipboardUtil mInstance;
   private ClipboardManager mClipboardManager;

   private Handler mHandler = new Handler();

   private ClipboardManager.OnPrimaryClipChangedListener onPrimaryClipChangedListener = new ClipboardManager.OnPrimaryClipChangedListener() {
       @Override
       public void onPrimaryClipChanged() {
           mHandler.removeCallbacks(mRunnable);
           mHandler.postDelayed(mRunnable, THRESHOLD);
       }
   };

   private ClipboardChangedRunnable mRunnable = new ClipboardChangedRunnable();

   private List<OnPrimaryClipChangedListener> mOnPrimaryClipChangedListeners = new ArrayList<>();

   /**
    * 自定义 OnPrimaryClipChangedListener
    * 用于处理某些情况下系统多次调用 onPrimaryClipChanged()
    */
   public interface OnPrimaryClipChangedListener {
       void onPrimaryClipChanged(ClipboardManager clipboardManager);
   }

   private class ClipboardChangedRunnable implements Runnable {

       @Override
       public void run() {
           for (OnPrimaryClipChangedListener listener : mOnPrimaryClipChangedListeners) {
               listener.onPrimaryClipChanged(mClipboardManager);
           }
       }
   }

   private ClipboardUtil(Context context) {
       mContext = context;
       mClipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
       mClipboardManager.addPrimaryClipChangedListener(onPrimaryClipChangedListener);
   }

   /**
    * 单例。暂时不清楚此处传 Activity 的 Context 是否会造成内存泄漏
    * 建议在 Application 的 onCreate 方法中实现
    *
    * @param context
    * @return
    */
   public static ClipboardUtil init(Context context) {
       if (mInstance == null) {
           mInstance = new ClipboardUtil(context);
       }
       return mInstance;
   }

   /**
    * 获取ClipboardUtil实例,记得初始化
    *
    * @return
    */
   public static ClipboardUtil getInstance() {
       return mInstance;
   }

   public void addOnPrimaryClipChangedListener(OnPrimaryClipChangedListener listener) {
       if (!mOnPrimaryClipChangedListeners.contains(listener)) {
           mOnPrimaryClipChangedListeners.add(listener);
       }
   }

   public void removeOnPrimaryClipChangedListener(OnPrimaryClipChangedListener listener) {
       mOnPrimaryClipChangedListeners.remove(listener);
   }

   /**
    * 判断剪贴板内是否有数据
    *
    * @return
    */
   public boolean hasPrimaryClip() {
       return mClipboardManager.hasPrimaryClip();
   }

   /**
    * 获取剪贴板中第一条String
    *
    * @return
    */
   public String getClipText() {
       if (!hasPrimaryClip()) {
           return null;
       }
       ClipData data = mClipboardManager.getPrimaryClip();
       if (data != null
               && mClipboardManager.getPrimaryClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
           return data.getItemAt(0).getText().toString();
       }
       return null;
   }

   /**
    * 获取剪贴板中第一条String
    *
    * @param context
    * @return
    */
   public String getClipText(Context context) {
       return getClipText(context, 0);
   }

   /**
    * 获取剪贴板中指定位置item的string
    *
    * @param context
    * @param index
    * @return
    */
   public String getClipText(Context context, int index) {
       if (!hasPrimaryClip()) {
           return null;
       }
       ClipData data = mClipboardManager.getPrimaryClip();
       if (data == null) {
           return null;
       }
       if (data.getItemCount() > index) {
           return data.getItemAt(index).coerceToText(context).toString();
       }
       return null;
   }

   /**
    * 将文本拷贝至剪贴板
    *
    * @param text
    */
   public void copyText(String label, String text) {
       ClipData clip = ClipData.newPlainText(label, text);
       mClipboardManager.setPrimaryClip(clip);
   }

   /**
    * 将HTML等富文本拷贝至剪贴板
    *
    * @param label
    * @param text
    * @param htmlText
    */
   public void copyHtmlText(String label, String text, String htmlText) {
       ClipData clip = ClipData.newHtmlText(label, text, htmlText);
       mClipboardManager.setPrimaryClip(clip);
   }

   /**
    * 将Intent拷贝至剪贴板
    *
    * @param label
    * @param intent
    */
   public void copyIntent(String label, Intent intent) {
       ClipData clip = ClipData.newIntent(label, intent);
       mClipboardManager.setPrimaryClip(clip);
   }

   /**
    * 将Uri拷贝至剪贴板
    * If the URI is a content: URI,
    * this will query the content provider for the MIME type of its data and
    * use that as the MIME type.  Otherwise, it will use the MIME type
    * {@link ClipDescription#MIMETYPE_TEXT_URILIST}.
    * 如 uri = "content://contacts/people",那么返回的MIME type将变成"vnd.android.cursor.dir/person"
    *
    * @param cr    ContentResolver used to get information about the URI.
    * @param label User-visible label for the clip data.
    * @param uri   The URI in the clip.
    */
   public void copyUri(ContentResolver cr, String label, Uri uri) {
       ClipData clip = ClipData.newUri(cr, label, uri);
       mClipboardManager.setPrimaryClip(clip);
   }

   /**
    * 将多组数据放入剪贴板中,如选中ListView多个Item,并将Item的数据一起放入剪贴板
    *
    * @param label    User-visible label for the clip data.
    * @param mimeType mimeType is one of them:{@link android.content.ClipDescription#MIMETYPE_TEXT_PLAIN},
    *                 {@link android.content.ClipDescription#MIMETYPE_TEXT_HTML},
    *                 {@link android.content.ClipDescription#MIMETYPE_TEXT_URILIST},
    *                 {@link android.content.ClipDescription#MIMETYPE_TEXT_INTENT}.
    * @param items    放入剪贴板中的数据
    */
   public void copyMultiple(String label, String mimeType, List<ClipData.Item> items) {
       if (items == null) {
           throw new NullPointerException("items is null");
       }
       int size = items.size();
       ClipData clip = new ClipData(label, new String[]{mimeType}, items.get(0));
       for (int i = 1; i < size; i++) {
           clip.addItem(items.get(i));
       }
       mClipboardManager.setPrimaryClip(clip);
   }

   public CharSequence coercePrimaryClipToText() {
       if (!hasPrimaryClip()) {
           return null;
       }
       return mClipboardManager.getPrimaryClip().getItemAt(0).coerceToText(mContext);
   }

   public CharSequence coercePrimaryClipToStyledText() {
       if (!hasPrimaryClip()) {
           return null;
       }
       return mClipboardManager.getPrimaryClip().getItemAt(0).coerceToStyledText(mContext);
   }

   public CharSequence coercePrimaryClipToHtmlText() {
       if (!hasPrimaryClip()) {
           return null;
       }
       return mClipboardManager.getPrimaryClip().getItemAt(0).coerceToHtmlText(mContext);
   }

   /**
    * 获取当前剪贴板内容的MimeType
    *
    * @return 当前剪贴板内容的MimeType
    */
   public String getPrimaryClipMimeType() {
       if (!hasPrimaryClip()) {
           return null;
       }
       return mClipboardManager.getPrimaryClipDescription().getMimeType(0);
   }

   /**
    * 获取剪贴板内容的MimeType
    *
    * @param clip 剪贴板内容
    * @return 剪贴板内容的MimeType
    */
   public String getClipMimeType(ClipData clip) {
       return clip.getDescription().getMimeType(0);
   }

   /**
    * 获取剪贴板内容的MimeType
    *
    * @param clipDescription 剪贴板内容描述
    * @return 剪贴板内容的MimeType
    */
   public String getClipMimeType(ClipDescription clipDescription) {
       return clipDescription.getMimeType(0);
   }

   /**
    * 清空剪贴板
    */
   public void clearClip() {
       mClipboardManager.setPrimaryClip(null);
   }

}