Android剪切板

作者: WilliamIT | 来源:发表于2018-12-09 16:26 被阅读2次

介绍

Android提供了一个强大的基于剪贴板的复制和粘贴框架。它既支持简单的数据类型,也支持复杂的数据类型,包括文本字符串、复杂的数据结构、文本和二进制流数据,甚至还支持应用程序资源。

如下图所示:


clip.png

由上图可以简单的得到Android剪切板模版主要由四个类构成:ClipboardManagerClipDataClipData.ItemClipDescription.

简单的描述:系统复制数据,就是创建一个ClipData对象放在ClipboardManager全局上.ClipData可以包括多条Item子数据,子数据中复制内容可以是text,url,intent,但是都是这些子数据都是来自一次复制,每次复制会覆盖之前的复制内容.同时,ClipData中包含一个ClipDescription,用于描述本次复制内容的MimeType.

核心类

  • ClipboardManager

系统服务全局的剪切板类.如何得到如下:

ClipboardManager mClipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);

定义当剪贴板上的主剪辑发生更改时调用的侦听器回调:OnPrimaryClipChangedListener.

// 添加剪贴板数据改变监听器
mClipboardManager.addPrimaryClipChangedListener(new ClipboardManager.OnPrimaryClipChangedListener() {
    @Override
    public void onPrimaryClipChanged() {
        // 剪贴板中的数据被改变,此方法将被回调
        System.out.println("onPrimaryClipChanged()");
    }
});

// 移除指定的剪贴板数据改变监听器
 mClipboardManager.removePrimaryClipChangedListener(listener);
  • ClipData.Item
    剪切板子数据类,它包含了texthtmlUri或者Intent数据,一个clip对象可以包含一个或多个Item对象。
    一起来看看它的属性:
        final CharSequence mText;
        final String mHtmlText;
        final Intent mIntent;
        Uri mUri;

就是一个数据类.

  • ClipDescription
    剪切板的描述类.包含了ClipData对象的metadata信息,一般情况mimeType只有一个.
    一起看看它的属性就知道干什么的类了.
public class ClipDescription implements Parcelable {
    //默认的MimeTYpe
    public static final String MIMETYPE_TEXT_PLAIN = "text/plain";

    public static final String MIMETYPE_TEXT_HTML = "text/html";
    
    public static final String MIMETYPE_TEXT_URILIST = "text/uri-list";

    public static final String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent";

    public static final String EXTRA_TARGET_COMPONENT_NAME =
            "android.content.extra.TARGET_COMPONENT_NAME";
    public static final String EXTRA_USER_SERIAL_NUMBER =    "android.content.extra.USER_SERIAL_NUMBER";
    //包含一个标签
    final CharSequence mLabel;
    //mimeType数组
    final String[] mMimeTypes;
    //可以保存额外的数据
    private PersistableBundle mExtras;
    ......
    
}

一般使用前面四种:text、html、uri、intent.其中url比较特殊.如果使用Android资源MimeType需要由ContentResolver提供.
什么是uri:

通用资源标志符(Universal Resource Identifier, 简称"URI")。
Uri代表要操作的数据,Android上可用的每种资源 - 图像、视频片段等都可以用Uri来表示。
Android的Uri由以下三部分组成: "content://"、数据的路径、标示ID(可选)

  • ClipData
    剪切对象,在有且仅有一个剪切板对象在系统服务中.言外之意,每一次复制前一次复制内容都会消失.
    一起来看看它的属性:
public class ClipData implements Parcelable {
    //默认mimetype。 text/plain
    static final String[] MIMETYPES_TEXT_PLAIN = new String[] {
        ClipDescription.MIMETYPE_TEXT_PLAIN };
    //text/html
    static final String[] MIMETYPES_TEXT_HTML = new String[] {
        ClipDescription.MIMETYPE_TEXT_HTML };
    //urllist
    static final String[] MIMETYPES_TEXT_URILIST = new String[] {
        ClipDescription.MIMETYPE_TEXT_URILIST };
    //intent
    static final String[] MIMETYPES_TEXT_INTENT = new String[] {
        ClipDescription.MIMETYPE_TEXT_INTENT };
    
    //剪切板描述类
    final ClipDescription mClipDescription;
    
    final Bitmap mIcon;
    
    //用于存放剪切板子数据
    final ArrayList<Item> mItems;

    .......
}

创建方式:

/**
     * Create a new ClipData holding data of the type
     * {@link ClipDescription#MIMETYPE_TEXT_PLAIN}.
     *
     * @param label User-visible label for the clip data.
     * @param text The actual text in the clip.
     * @return Returns a new ClipData containing the specified data.
     */
    static public ClipData newPlainText(CharSequence label, CharSequence text) {
        Item item = new Item(text);
        return new ClipData(label, MIMETYPES_TEXT_PLAIN, item);
    }

    /**
     * Create a new ClipData holding data of the type
     * {@link ClipDescription#MIMETYPE_TEXT_HTML}.
     *
     * @param label User-visible label for the clip data.
     * @param text The text of clip as plain text, for receivers that don't
     * handle HTML.  This is required.
     * @param htmlText The actual HTML text in the clip.
     * @return Returns a new ClipData containing the specified data.
     */
    static public ClipData newHtmlText(CharSequence label, CharSequence text,
            String htmlText) {
        Item item = new Item(text, htmlText);
        return new ClipData(label, MIMETYPES_TEXT_HTML, item);
    }

    /**
     * Create a new ClipData holding an Intent with MIME type
     * {@link ClipDescription#MIMETYPE_TEXT_INTENT}.
     *
     * @param label User-visible label for the clip data.
     * @param intent The actual Intent in the clip.
     * @return Returns a new ClipData containing the specified data.
     */
    static public ClipData newIntent(CharSequence label, Intent intent) {
        Item item = new Item(intent);
        return new ClipData(label, MIMETYPES_TEXT_INTENT, item);
    }

    /**
     * Create a new ClipData holding a 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}.
     *
     * @param resolver ContentResolver used to get information about the URI.
     * @param label User-visible label for the clip data.
     * @param uri The URI in the clip.
     * @return Returns a new ClipData containing the specified data.
     */
    static public ClipData newUri(ContentResolver resolver, CharSequence label,
            Uri uri) {
        //创建item
        Item item = new Item(uri);
        /*获取mimeType*/
        String[] mimeTypes = null;
        if ("content".equals(uri.getScheme())) {
            String realType = resolver.getType(uri);
            mimeTypes = resolver.getStreamTypes(uri, "*/*");
            if (realType != null) {
                if (mimeTypes == null) {
                    mimeTypes = new String[] { realType };
                } else {
                    String[] tmp = new String[mimeTypes.length + 1];
                    tmp[0] = realType;
                    System.arraycopy(mimeTypes, 0, tmp, 1, mimeTypes.length);
                    mimeTypes = tmp;
                }
            }
        }
        if (mimeTypes == null) {
            mimeTypes = MIMETYPES_TEXT_URILIST;
        }
        return new ClipData(label, mimeTypes, item);
    }

    /**
     * Create a new ClipData holding an URI with MIME type
     * {@link ClipDescription#MIMETYPE_TEXT_URILIST}.
     * Unlike {@link #newUri(ContentResolver, CharSequence, Uri)}, nothing
     * is inferred about the URI -- if it is a content: URI holding a bitmap,
     * the reported type will still be uri-list.  Use this with care!
     *
     * @param label User-visible label for the clip data.
     * @param uri The URI in the clip.
     * @return Returns a new ClipData containing the specified data.
     */
    static public ClipData newRawUri(CharSequence label, Uri uri) {
        //创建item
        Item item = new Item(uri);
        return new ClipData(label, MIMETYPES_TEXT_URILIST, item);
    }

clipData对象创建后塞入Clipboardmanager即可:

//Clipboardmanager方法
/**
     * Sets the current primary clip on the clipboard.  This is the clip that
     * is involved in normal cut and paste operations.
     *
     * @param clip The clipped data item to set.
     */
    public void setPrimaryClip(ClipData clip) {
        try {
            if (clip != null) {
                clip.prepareToLeaveProcess(true);
            }
            getService().setPrimaryClip(clip, mContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

  • 转换成字符串
//任何作为HTML格式返回的文本都将作为具有样式跨度的文本返回。
CharSequence coerceToStyledText(Context context);

//如果getText()是非空的,则返回该值。
//如果getUri()非null,则尝试从其内容提供程序检索其数据作为文本流。如果成功,将文本复制到字符串中并返回。如果它不是内容:URI或内容提供程序不提供文本表示,则将原始URI作为字符串返回。
//如果getIntent()非null,则将其转换为intent: URI并返回。
//否则,返回一个空字符串。
CharSequence coerceToText(Context context) ;

//如果getHtmlText()非null,则返回该值。
//如果getText()是非空的,返回它,转换为有效的HTML文本。如果此文本包含样式跨度,则使用HTML . tohtml (span)将其转换为HTML格式。
//如果getUri()非null,则尝试从其内容提供程序检索其数据作为文本流。
//如果提供程序可以提供文本/html数据,则首选该数据并按原样返回。否则,将返回任何文本/*数据并转义到HTML。
//如果它不是内容:URI或内容提供程序不提供文本表示,将返回包含到URI链接的HTML文本。
//如果getIntent()非null,则将其转换为intent: URI并以HTML链接的形式返回。
//否则,返回一个空字符串。
String coerceToHtmlText(Context context) 

详细的内容可以查看官网,地址我也写出来了,在最下面,哈哈哈.

  • 注意
    1、剪切板只会保存最近一次复制的内容.
    2、MimeType一般只有一个.(可以有多个)
    3、系统全局的剪切板,其他应用也可以使用.

工具类


package com.rnx.react.modules.clip;

import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ClipboardManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;

import java.util.List;

/**
 * @Auther: weiwei.zhang06
 * @Date: 2018/12/5 18:59
 */

public class ClipboardHelper {

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

  private Context mContext;
  private volatile static ClipboardHelper mInstance;
  private ClipboardManager mClipboardManager;

  private ClipboardHelper(Context context) {
    mContext = context;
    mClipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
  }

  /**
   * 获取ClipboardUtil实例,记得初始化
   *
   * @return 单例
   */
  public static ClipboardHelper getInstance(Context context) {
    if (mInstance == null) {
      synchronized (ClipboardHelper.class) {
        if (mInstance == null) {
          mInstance = new ClipboardHelper(context.getApplicationContext());
        }
      }
    }
    return mInstance;
  }

  /**
   * 判断剪贴板内是否有数据
   *
   * @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 ClipDescription#MIMETYPE_TEXT_PLAIN},
   *                 {@link ClipDescription#MIMETYPE_TEXT_HTML},
   *                 {@link ClipDescription#MIMETYPE_TEXT_URILIST},
   *                 {@link ClipDescription#MIMETYPE_TEXT_INTENT}.
   * @param items    放入剪贴板中的数据
   */
  public void copyMultiple(String label, String mimeType, List<ClipData.Item> items) {
    if (items == null || items.size() == 0) {
      throw new IllegalArgumentException("argument: items error");
    }
    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 void copyMultiple(String label, String[] mimeTypes, List<ClipData.Item> items) {
    if (items == null || items.size() == 0) {
      throw new IllegalArgumentException("argument: items error");
    }
    int size = items.size();
    ClipData clip = new ClipData(label, mimeTypes, 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(ClipData.newPlainText(null, ""));
  }

  public ClipData getClipData() {
    if (!hasPrimaryClip()) {
      return null;
    }
    return mClipboardManager.getPrimaryClip();
  }
}


官网: https://developer.android.com/guide/topics/text/copy-paste#java

ClipboardManger api: https://developer.android.com/reference/android/content/ClipboardManager

ClipData api: https://developer.android.com/reference/android/content/ClipData

ClipData.item api: https://developer.android.com/reference/android/content/ClipData.Item

ClipDescription api: https://developer.android.com/reference/android/content/ClipDescription


感谢阅读

相关文章

  • Android 剪切板ClipboardManager过时问题

    Android 剪切板ClipboardManager过时问题 导入包注意 API 11之前: android.t...

  • android之ClipboardManager使用

    ClipboardManager ClipboardManager是Android系统剪贴板的主要类。使用剪切板功...

  • android剪切板操作

    前言 在Android开发过程中偶尔会涉及到剪切板相关操作。今天,就让我们来学习下剪切板实现的一些功能吧。我把剪切...

  • android剪切板

    剪切板的管理类ClipboardManager在API11之后,包含在android.content中,impor...

  • Android剪切板

    介绍 Android提供了一个强大的基于剪贴板的复制和粘贴框架。它既支持简单的数据类型,也支持复杂的数据类型,包括...

  • 3.5 UiPath剪贴板操作的介绍和使用

    剪切板操作的介绍模拟用户使用剪切板操作的一种行为:例如使用设置剪切板(SettoClipboard),从剪切板获取...

  • adb 命令 pc端 "复制粘贴" 文本到a

    假如你像我一样在寻找android下通过命令复制粘贴的方法。不过android上是没有直接进行复制粘贴剪切板的命令...

  • Android6.0之App获取系统service的过程

    Android系统中提供了很多Service,如剪切板服务,AMS服务等.很有必要一个app是如何获得这些serv...

  • service2-App获取系统service的过程

    Android系统中提供了很多Service,如剪切板服务,AMS服务等.很有必要一个app是如何获得这些serv...

  • python 操作剪切板

    有时候写脚本的时候会有操作系统剪切板的需求,就是 获取剪切板中的字符串 清空剪切板 向剪切板中写入字符串 方法包括...

网友评论

    本文标题:Android剪切板

    本文链接:https://www.haomeiwen.com/subject/tdckhqtx.html