Android剪切板

介紹

Android提供了一個(gè)強(qiáng)大的基于剪貼板的復(fù)制和粘貼框架拧烦。它既支持簡(jiǎn)單的數(shù)據(jù)類型,也支持復(fù)雜的數(shù)據(jù)類型莉擒,包括文本字符串翰蠢、復(fù)雜的數(shù)據(jù)結(jié)構(gòu)、文本和二進(jìn)制流數(shù)據(jù)啰劲,甚至還支持應(yīng)用程序資源梁沧。

如下圖所示:


clip.png

由上圖可以簡(jiǎn)單的得到Android剪切板模版主要由四個(gè)類構(gòu)成:ClipboardManagerClipData蝇裤、ClipData.Item廷支、ClipDescription.

簡(jiǎn)單的描述:系統(tǒng)復(fù)制數(shù)據(jù),就是創(chuàng)建一個(gè)ClipData對(duì)象放在ClipboardManager全局上.ClipData可以包括多條Item子數(shù)據(jù),子數(shù)據(jù)中復(fù)制內(nèi)容可以是text,url,intent,但是都是這些子數(shù)據(jù)都是來(lái)自一次復(fù)制,每次復(fù)制會(huì)覆蓋之前的復(fù)制內(nèi)容.同時(shí),ClipData中包含一個(gè)ClipDescription,用于描述本次復(fù)制內(nèi)容的MimeType.

核心類

  • ClipboardManager

系統(tǒng)服務(wù)全局的剪切板類.如何得到如下:

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

定義當(dāng)剪貼板上的主剪輯發(fā)生更改時(shí)調(diào)用的偵聽(tīng)器回調(diào):OnPrimaryClipChangedListener.

// 添加剪貼板數(shù)據(jù)改變監(jiān)聽(tīng)器
mClipboardManager.addPrimaryClipChangedListener(new ClipboardManager.OnPrimaryClipChangedListener() {
    @Override
    public void onPrimaryClipChanged() {
        // 剪貼板中的數(shù)據(jù)被改變,此方法將被回調(diào)
        System.out.println("onPrimaryClipChanged()");
    }
});

// 移除指定的剪貼板數(shù)據(jù)改變監(jiān)聽(tīng)器
 mClipboardManager.removePrimaryClipChangedListener(listener);
  • ClipData.Item
    剪切板子數(shù)據(jù)類,它包含了text栓辜、html恋拍、Uri或者Intent數(shù)據(jù),一個(gè)clip對(duì)象可以包含一個(gè)或多個(gè)Item對(duì)象藕甩。
    一起來(lái)看看它的屬性:
        final CharSequence mText;
        final String mHtmlText;
        final Intent mIntent;
        Uri mUri;

就是一個(gè)數(shù)據(jù)類.

  • ClipDescription
    剪切板的描述類.包含了ClipData對(duì)象的metadata信息,一般情況mimeType只有一個(gè).
    一起看看它的屬性就知道干什么的類了.
public class ClipDescription implements Parcelable {
    //默認(rèn)的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";
    //包含一個(gè)標(biāo)簽
    final CharSequence mLabel;
    //mimeType數(shù)組
    final String[] mMimeTypes;
    //可以保存額外的數(shù)據(jù)
    private PersistableBundle mExtras;
    ......
    
}

一般使用前面四種:text施敢、html、uri狭莱、intent.其中url比較特殊.如果使用Android資源MimeType需要由ContentResolver提供.
什么是uri:

通用資源標(biāo)志符(Universal Resource Identifier, 簡(jiǎn)稱"URI")僵娃。
Uri代表要操作的數(shù)據(jù),Android上可用的每種資源 - 圖像腋妙、視頻片段等都可以用Uri來(lái)表示默怨。
Android的Uri由以下三部分組成: "content://"、數(shù)據(jù)的路徑骤素、標(biāo)示ID(可選)

  • ClipData
    剪切對(duì)象,在有且僅有一個(gè)剪切板對(duì)象在系統(tǒng)服務(wù)中.言外之意,每一次復(fù)制前一次復(fù)制內(nèi)容都會(huì)消失.
    一起來(lái)看看它的屬性:
public class ClipData implements Parcelable {
    //默認(rèn)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;
    
    //用于存放剪切板子數(shù)據(jù)
    final ArrayList<Item> mItems;

    .......
}

創(chuàng)建方式:

/**
     * 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) {
        //創(chuàng)建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) {
        //創(chuàng)建item
        Item item = new Item(uri);
        return new ClipData(label, MIMETYPES_TEXT_URILIST, item);
    }

clipData對(duì)象創(chuàng)建后塞入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();
        }
    }

  • 轉(zhuǎn)換成字符串
//任何作為HTML格式返回的文本都將作為具有樣式跨度的文本返回。
CharSequence coerceToStyledText(Context context);

//如果getText()是非空的济竹,則返回該值痕檬。
//如果getUri()非null,則嘗試從其內(nèi)容提供程序檢索其數(shù)據(jù)作為文本流送浊。如果成功梦谜,將文本復(fù)制到字符串中并返回。如果它不是內(nèi)容:URI或內(nèi)容提供程序不提供文本表示,則將原始URI作為字符串返回改淑。
//如果getIntent()非null碍岔,則將其轉(zhuǎn)換為intent: URI并返回。
//否則朵夏,返回一個(gè)空字符串蔼啦。
CharSequence coerceToText(Context context) ;

//如果getHtmlText()非null,則返回該值仰猖。
//如果getText()是非空的捏肢,返回它,轉(zhuǎn)換為有效的HTML文本饥侵。如果此文本包含樣式跨度鸵赫,則使用HTML . tohtml (span)將其轉(zhuǎn)換為HTML格式。
//如果getUri()非null躏升,則嘗試從其內(nèi)容提供程序檢索其數(shù)據(jù)作為文本流辩棒。
//如果提供程序可以提供文本/html數(shù)據(jù),則首選該數(shù)據(jù)并按原樣返回膨疏。否則一睁,將返回任何文本/*數(shù)據(jù)并轉(zhuǎn)義到HTML。
//如果它不是內(nèi)容:URI或內(nèi)容提供程序不提供文本表示佃却,將返回包含到URI鏈接的HTML文本者吁。
//如果getIntent()非null,則將其轉(zhuǎn)換為intent: URI并以HTML鏈接的形式返回饲帅。
//否則复凳,返回一個(gè)空字符串。
String coerceToHtmlText(Context context) 

詳細(xì)的內(nèi)容可以查看官網(wǎng),地址我也寫(xiě)出來(lái)了,在最下面,哈哈哈.

  • 注意
    1灶泵、剪切板只會(huì)保存最近一次復(fù)制的內(nèi)容.
    2育八、MimeType一般只有一個(gè).(可以有多個(gè))
    3、系統(tǒng)全局的剪切板,其他應(yīng)用也可以使用.

工具類


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實(shí)例丘逸,記得初始化
   *
   * @return 單例
   */
  public static ClipboardHelper getInstance(Context context) {
    if (mInstance == null) {
      synchronized (ClipboardHelper.class) {
        if (mInstance == null) {
          mInstance = new ClipboardHelper(context.getApplicationContext());
        }
      }
    }
    return mInstance;
  }

  /**
   * 判斷剪貼板內(nèi)是否有數(shù)據(jù)
   *
   * @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);
  }

  /**
   * 將多組數(shù)據(jù)放入剪貼板中,如選中ListView多個(gè)Item深纲,并將Item的數(shù)據(jù)一起放入剪貼板
   *
   * @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    放入剪貼板中的數(shù)據(jù)
   */
  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);
  }

  /**
   * 獲取當(dāng)前剪貼板內(nèi)容的MimeType
   *
   * @return 當(dāng)前剪貼板內(nèi)容的MimeType
   */
  public String getPrimaryClipMimeType() {
    if (!hasPrimaryClip()) {
      return null;
    }
    return mClipboardManager.getPrimaryClipDescription().getMimeType(0);
  }

  /**
   * 獲取剪貼板內(nèi)容的MimeType
   *
   * @param clip 剪貼板內(nèi)容
   * @return 剪貼板內(nèi)容的MimeType
   */
  public String getClipMimeType(ClipData clip) {
    return clip.getDescription().getMimeType(0);
  }

  /**
   * 獲取剪貼板內(nèi)容的MimeType
   *
   * @param clipDescription 剪貼板內(nèi)容描述
   * @return 剪貼板內(nèi)容的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();
  }
}


官網(wǎng): 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


感謝閱讀

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市劲妙,隨后出現(xiàn)的幾起案子湃鹊,更是在濱河造成了極大的恐慌,老刑警劉巖镣奋,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件币呵,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)余赢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)芯义,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人妻柒,你說(shuō)我怎么就攤上這事扛拨。” “怎么了举塔?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵绑警,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我央渣,道長(zhǎng)计盒,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任芽丹,我火速辦了婚禮北启,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拔第。我一直安慰自己咕村,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布楼肪。 她就那樣靜靜地躺著培廓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪春叫。 梳的紋絲不亂的頭發(fā)上肩钠,一...
    開(kāi)封第一講書(shū)人閱讀 51,737評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音暂殖,去河邊找鬼价匠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛呛每,可吹牛的內(nèi)容都是我干的踩窖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼晨横,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼洋腮!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起手形,我...
    開(kāi)封第一講書(shū)人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤啥供,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后库糠,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體伙狐,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贷屎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罢防。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖唉侄,靈堂內(nèi)的尸體忽然破棺而出咒吐,到底是詐尸還是另有隱情,我是刑警寧澤美旧,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布渤滞,位于F島的核電站,受9級(jí)特大地震影響榴嗅,放射性物質(zhì)發(fā)生泄漏妄呕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一嗽测、第九天 我趴在偏房一處隱蔽的房頂上張望绪励。 院中可真熱鬧,春花似錦唠粥、人聲如沸疏魏。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)大莫。三九已至,卻和暖如春官份,著一層夾襖步出監(jiān)牢的瞬間只厘,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工舅巷, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留羔味,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓钠右,卻偏偏與公主長(zhǎng)得像赋元,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子飒房,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容