Android窗口系統(tǒng)第一篇---Window的類(lèi)型與Z-Order確定

Android的窗口系統(tǒng)是UI架構(gòu)很重要的一部分承璃,數(shù)據(jù)結(jié)構(gòu)比較多利耍,細(xì)節(jié)比較多。本篇文章主要介紹窗口相關(guān)數(shù)據(jù)結(jié)構(gòu)和抽象概念理解盔粹,關(guān)于[窗口部分的博客]計(jì)劃如下隘梨。
1、窗口Z-Order的管理
2舷嗡、應(yīng)用程序和WMS的聯(lián)系
3轴猎、窗口的添加,WindowState的創(chuàng)建
4进萄、Token管理捻脖,AppToken
5、窗口大小的計(jì)算
6中鼠、啟動(dòng)窗口
7郎仆、窗口的切換和動(dòng)畫(huà)
8、多窗口兜蠕,分屏、畫(huà)中畫(huà)抛寝,自由模式的實(shí)現(xiàn)思路
9熊杨、View的測(cè)量和布局
10、桌面啟動(dòng)流程
11盗舰、墻紙流程

本篇文章主要討論窗口類(lèi)型晶府、坐標(biāo)系統(tǒng)、Z-Order,Z-Order確定跟窗口類(lèi)型有關(guān)系钻趋,先看窗口類(lèi)型川陆。

一、窗口類(lèi)型

1.1蛮位、Window的類(lèi)型

Android系統(tǒng)的Window有很多個(gè)较沪,大體上來(lái)說(shuō)鳞绕,F(xiàn)ramework定義了三種窗口類(lèi)型;

系統(tǒng)Window
常見(jiàn)的系統(tǒng)Window有哪些呢尸曼?比如在手機(jī)電量低的時(shí)候们何,會(huì)有一個(gè)提示電量低的Window,我們輸入文字的時(shí)候,會(huì)彈出輸入法Window,還有搜索條Window,來(lái)電顯示W(wǎng)indow,Toast對(duì)應(yīng)的Window,可以總結(jié)出來(lái)控轿,系統(tǒng)Window是獨(dú)立與我們的應(yīng)用程序的冤竹,對(duì)于應(yīng)用程序而言,我們理論上是無(wú)法創(chuàng)建系統(tǒng)Window茬射,因?yàn)闆](méi)有權(quán)限鹦蠕,這個(gè)權(quán)限只有系統(tǒng)進(jìn)程有。

應(yīng)用程序Window
所謂應(yīng)用窗口指的就是該窗口對(duì)應(yīng)一個(gè)Activity在抛,因此钟病,要?jiǎng)?chuàng)建應(yīng)用窗口就必須在Activity中完成了。本節(jié)后面會(huì)分析Activity對(duì)應(yīng)的Window的創(chuàng)建過(guò)程霜定。

子Window
所謂的子Window档悠,是說(shuō)這個(gè)Window必須要有一個(gè)父窗體,比如PopWindow望浩,Dialog是屬于應(yīng)用程序Window,這個(gè)比較特殊辖所。

每一種窗口類(lèi)型定義了一種對(duì)應(yīng)的type
應(yīng)用類(lèi)型的窗口的type范圍是1~99


應(yīng)用類(lèi)型的窗口

子窗口的type范圍是1000~1999


子窗口

系統(tǒng)的窗口的type范圍是2000以上 


i系統(tǒng)的窗口

系統(tǒng)窗口的type值>子窗口的type值>應(yīng)用類(lèi)型窗口的type值,一般來(lái)說(shuō)磨德,根據(jù)type值大小關(guān)系缘回,可以推出系統(tǒng)窗口在子窗口的上面,子窗口在應(yīng)用窗口的上面典挑。

二酥宴、窗口布局和Z序

窗口的布局一般有兩種,一種是平鋪式的布局您觉,一種是層疊式的布局

平鋪窗口布局

平鋪式的布局設(shè)計(jì)簡(jiǎn)單拙寡,現(xiàn)在還有一些終端系統(tǒng)仍然是單窗口的平鋪布局,手機(jī)上采用的是層疊式布局琳水,層疊式布局是一個(gè)三維的空間肆糕,將手機(jī)的水平方向作為X軸,豎直方向作為Y軸在孝,還有一根垂直與屏幕從里朝外方向的虛擬的Z軸诚啃,所有窗口 (WindowState) 按照順序排列在Z軸上,如下圖私沮。

層疊式布局

2.1始赎、窗口主序的確定

WindowState是WMS中事實(shí)的窗口,而不是Window,WindowState是在WMS的addWindow方法中創(chuàng)建造垛,包含了一個(gè)窗口的所有的屬性魔招,其中一個(gè)屬性為mLayer,表示窗口在Z軸的位置筋搏,mLayer值越小仆百,窗口越靠后,mLayer值越大奔脐,窗口越靠前俄周,最前面的一個(gè)窗口就作為焦點(diǎn)窗口,可以接收觸摸事件髓迎。因?yàn)榇翱诘那袚Q峦朗,切換后的Z序(窗口的顯示次序稱(chēng)為 Z 序)就可能不同,所以mLayer的值不是固定不變的排龄。mLayer是通過(guò)WindowState的另一個(gè)成員變量mBaseLayer的值計(jì)算得到波势,mBaseLayer的值是固定不變的,只和窗口類(lèi)型有關(guān)橄维。mBaseLayer(稱(chēng)為主序)是WindowState的構(gòu)造方法中賦值尺铣。

mBaseLayer = mPolicy.windowTypeToLayerLw(
                   attachedWindow.mAttrs.type) * WindowManagerService.TYPE_LAYER_MULTIPLIER
                   + WindowManagerService.TYPE_LAYER_OFFSET;

等價(jià)與:mBaseLayer =窗口類(lèi)型×10000+1000
windowTypeToLayerLw根據(jù)窗口的類(lèi)型type,返回2開(kāi)始的整數(shù)值

public int windowTypeToLayerLw(int type) {
       if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
           return 2;
       }
       switch (type) {
       case TYPE_WALLPAPER:
             return 2;
           // wallpaper is at the bottom, though the window manager may move it.
       case TYPE_PHONE:
           return 3;
      .....
    case TYPE_TOAST:
           // toasts and the plugged-in battery thing
           return 8;
        .....
       case TYPE_BOOT_PROGRESS:
           return 30;
       case TYPE_POINTER:
           // the (mouse) pointer layer
           return 31;
       }
       Log.e(TAG, "Unknown window type: " + type);
       return 2;

可以看到系統(tǒng)中的窗口種類(lèi)比較多争舞,case個(gè)數(shù)都到31了凛忿。比如應(yīng)用程序的窗口是2,電話類(lèi)型的窗口是3竞川,Toast窗口是8...店溢,因?yàn)橄到y(tǒng)中同類(lèi)型的窗口比較多,所以對(duì)返回的整數(shù)值乘以10000(WindowManagerService.TYPE_LAYER_MULTIPLIER)委乌,在加上1000(WindowManagerService.TYPE_LAYER_OFFSET)床牧,相當(dāng)把Z軸劃分成了31個(gè)值域,不同類(lèi)型的窗口的Z軸位置都是處于兩個(gè)不相交的值域之中遭贸,互相不打擾戈咳。OK,通過(guò)mBaseLayer壕吹,我們知道了窗口是如何排序的著蛙,一個(gè)窗口有可能需要依附在一個(gè)父窗口上,作為一個(gè)子窗口算利,所以除了主序的概念外,還有子序泳姐。

2.2效拭、窗口子序的確定

SubLayer(稱(chēng)為子序),SubLayer值是用來(lái)描述一個(gè)窗口是否屬于另外一個(gè)窗口的子窗口,或者說(shuō)SubLayer值是用來(lái)確定子窗口和父窗口之間的相對(duì)位置的缎患。

SubLayer.png

一個(gè)Activity中有三個(gè)子窗口WindowState1慕的、WindowState2、WindowState3挤渔,WindowState1WindowState2在窗口A的前面肮街,WindowState3在A的后面,這幾個(gè)兄弟窗口為什么可以這樣排序呢判导,這就是mSubLayer的作用嫉父,子序越大,則相對(duì)其他兄弟窗口越靠前眼刃,反之绕辖,越靠后,如果為負(fù)數(shù)擂红,就處在父窗口的后面仪际,如窗口A中的WindowState3,子序是根據(jù)窗口類(lèi)型調(diào)用subWindowTypeToLayerLw確定的昵骤,subWindowTypeToLayerLw同樣是在Window的構(gòu)造方法中調(diào)用的树碱。

  mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
 public int subWindowTypeToLayerLw(int type) {
       switch (type) {
       case TYPE_APPLICATION_PANEL:
       case TYPE_APPLICATION_ATTACHED_DIALOG:
           return APPLICATION_PANEL_SUBLAYER;//返回值是1
       case TYPE_APPLICATION_MEDIA:
           return APPLICATION_MEDIA_SUBLAYER;//返回值是-2  
       case TYPE_APPLICATION_MEDIA_OVERLAY:
           return APPLICATION_MEDIA_OVERLAY_SUBLAYER;//返回值是-1  
       case TYPE_APPLICATION_SUB_PANEL:
           return APPLICATION_SUB_PANEL_SUBLAYER;//返回值是2 
       case TYPE_APPLICATION_ABOVE_SUB_PANEL:
           return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER;//返回值是3  
       }
       Log.e(TAG, "Unknown sub-window type: " + type);
       return 0;
   }

相對(duì)與主序的確定,子序是非常簡(jiǎn)單了变秦,但是成榜,假設(shè)系統(tǒng)中有個(gè)應(yīng)用程序現(xiàn)在有5個(gè)窗口,全部都是應(yīng)用類(lèi)型的窗口伴栓,按照上面的規(guī)則伦连,計(jì)算出來(lái)的主序應(yīng)該相同,如何排序钳垮? 這就需要WMS進(jìn)行后期的調(diào)整惑淳。

2.3、窗口Z序的調(diào)整

當(dāng)WindowState創(chuàng)建完成饺窿,并且被添加到WMS維持的數(shù)組里面后歧焦,就需要調(diào)用WindowLayersController的assignLayersLocked(windows),進(jìn)行Z序的調(diào)整肚医。

//參數(shù)windows是窗口列表
final void assignLayersLocked(WindowList windows) {
       if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based on windows=" + windows,
               new RuntimeException("here").fillInStackTrace());

       clear();
       int curBaseLayer = 0;
       int curLayer = 0;
       boolean anyLayerChanged = false;
      //遍歷窗口列表绢馍,上面通過(guò)Z序的計(jì)算公式計(jì)算出來(lái)的Z序值保存在WindowState的變量mBaseLayer
       中,這個(gè)循環(huán)的意思是肠套,遇到同類(lèi)型的窗口舰涌,后一個(gè)窗口在前一個(gè)窗口的基礎(chǔ)上偏移5。
       for (int i = 0, windowCount = windows.size(); i < windowCount; i++) {
           final WindowState w = windows.get(i);
           boolean layerChanged = false;

           int oldLayer = w.mLayer;
           if (w.mBaseLayer == curBaseLayer || w.mIsImWindow || (i > 0 && w.mIsWallpaper)) {
               curLayer += WINDOW_LAYER_MULTIPLIER;
           } else {
               curBaseLayer = curLayer = w.mBaseLayer;
           }
          // 更新該窗口的mAnimLayer你稚,也就是動(dòng)畫(huà)顯示時(shí)瓷耙,該窗口的層級(jí)
           assignAnimLayer(w, curLayer);

           // TODO: Preserved old behavior of code here but not sure comparing
           // oldLayer to mAnimLayer and mLayer makes sense...though the
           // worst case would be unintentionalp layer reassignment.
           if (w.mLayer != oldLayer || w.mWinAnimator.mAnimLayer != oldLayer) {
               layerChanged = true;
               anyLayerChanged = true;
           }

     // 將當(dāng)前應(yīng)用窗口的最高顯示層級(jí)記錄在mHighestApplicationLayer中
           if (w.mAppToken != null) {
               mHighestApplicationLayer = Math.max(mHighestApplicationLayer,
                       w.mWinAnimator.mAnimLayer);
           }
          //  對(duì)于分屏等相關(guān)的窗口朱躺,它們的顯示層級(jí)需要再次處理
           collectSpecialWindows(w);

           if (layerChanged) {
               w.scheduleAnimationIfDimming();
           }
       }

    // 調(diào)整特殊窗口的層級(jí)
       adjustSpecialWindows();

       //TODO (multidisplay): Magnification is supported only for the default display.
       if (mService.mAccessibilityController != null && anyLayerChanged
               && windows.get(windows.size() - 1).getDisplayId() == Display.DEFAULT_DISPLAY) {
           mService.mAccessibilityController.onWindowLayersChangedLocked();
       }

       if (DEBUG_LAYERS) logDebugLayers(windows);
   }

經(jīng)過(guò)調(diào)整之后,同類(lèi)型的窗口的Z序值就不同了搁痛。

3长搀、窗口Z序的深入理解

1、Layer值為何乘以1萬(wàn)?

Layer的計(jì)算公式為:

   mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)  * WindowManagerService.TYPE_LAYER_MULTIPLIER   + WindowManagerService.TYPE_LAYER_OFFSET; 
等價(jià)與:mBaseLayer =窗口類(lèi)型×10000+1000

其中TYPE_LAYER_MULTIPLIER和TYPE_LAYER_OFFSET在WMS的聲明如下鸡典,

/** How much to multiply the policy's type layer, to reserve room
 * for multiple windows of the same type and Z-ordering adjustment
 * with TYPE_LAYER_OFFSET. 
  */
static final int TYPE_LAYER_MULTIPLIER = 10000;

/** Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above
  * or below others in the same layer. 
  */
static final int TYPE_LAYER_OFFSET = 1000;

mBaseLayer的值是在WindowState的構(gòu)造中計(jì)算的源请,子窗口和一般窗口計(jì)算有所不同
if ((mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW)) {//如果是子窗口  
   // The multiplier here is to reserve space for multiple  
   // windows in the same type layer.  
    //使用依附窗口的類(lèi)型 
   mBaseLayer = mPolicy.windowTypeToLayerLw(attachedWindow.mAttrs.type) * WindowManagerService.TYPE_LAYER_MULTIPLIER  
           + WindowManagerService.TYPE_LAYER_OFFSET;  
   mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);//計(jì)算mSubLayer  
   ......  
} else {//非子窗口  
   // The multiplier here is to reserve space for multiple  
   // windows in the same type layer.  
   mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)  
           * WindowManagerService.TYPE_LAYER_MULTIPLIER  
           + WindowManagerService.TYPE_LAYER_OFFSET;  
   mSubLayer = 0;  
   ......  
} 

Layer值為什么要乘以10000萬(wàn)呢?PhoneWindowManager對(duì)象mPolicy的成員函數(shù)windowTypeToLayerLw的返回值并且不是一個(gè)窗口的最終的BaseLayer值彻况,而是要將它的返回值乘以一個(gè)常量TYPE_LAYER_MULTIPLIER(10000)谁尸,再加上另外一個(gè)常量TYPE_LAYER_OFFSET(1000)之后,才得到最終的BaseLayer值疗垛。這是因?yàn)橄嗤?lèi)型的窗口的Z軸位置都是有著相同的值域症汹,而不同類(lèi)型的窗口的Z軸位置都是處于兩個(gè)不相交的值域。例如贷腕,假設(shè)有兩種不同類(lèi)型的窗口背镇,它們的Z軸位置的值域分別為[a, b]和[c, d],那么[a, b]和[c, d]的交集一定等于空泽裳。又由于每一種類(lèi)型的窗口的數(shù)量是不確定的瞒斩,因此,WindowManagerService服務(wù)就需要為每一種類(lèi)型的窗口都預(yù)留一個(gè)范圍足夠大的值域涮总,以便可以滿足要求胸囱。

2、Z序調(diào)整為何加5而不加其他數(shù)字

Z序的調(diào)整是在WindowLayersController的assignLayersLocked方法實(shí)現(xiàn)的瀑梗。所謂的調(diào)整就是遍歷窗口列表烹笔,如果窗口的mBaseLayer和前一個(gè)相同、或者是輸入法和壁紙窗口就加上常量值WINDOW_LAYER_MULTIPLIER抛丽。

private final void assignLayersLocked(WindowList windows) {  
   int N = windows.size();  
   int curBaseLayer = 0;  
   int curLayer = 0;  
   int i;  
  
   boolean anyLayerChanged = false;  
  
   for (i=0; i<N; i++) {  
       final WindowState w = windows.get(i);  
       final WindowStateAnimator winAnimator = w.mWinAnimator;  
       boolean layerChanged = false;  
       int oldLayer = w.mLayer;  
       if (w.mBaseLayer == curBaseLayer || w.mIsImWindow  || (i > 0 && w.mIsWallpaper)) {  
           curLayer += WINDOW_LAYER_MULTIPLIER;  
           w.mLayer = curLayer;  
       } else {  
           curBaseLayer = curLayer = w.mBaseLayer;  
           w.mLayer = curLayer;  
       }  
      ....... 
   }  
   .......
}  

WINDOW_LAYER_MULTIPLIER在WMS的聲明如下

/** How much to increment the layer for each window, to reserve room
 * for effect surfaces between them.
 */
static final int WINDOW_LAYER_MULTIPLIER = 5;

意思為在每個(gè)窗口層之間預(yù)留空間谤职。加上5之后,在同層的窗口中每隔一個(gè)窗口就留下4個(gè)空位亿鲜, 如果加上1允蜈,按道理來(lái)說(shuō)也行,為了搞清楚為什么加5蒿柳,我給google維護(hù)窗口系統(tǒng)的工程師發(fā)了一封郵件饶套。

google-mail.png

但是很遺憾,一直沒(méi)有收到回信垒探,但是應(yīng)該可以確定妓蛮,這里加1也是可以的,同樣可以使得同類(lèi)型的窗口的Z序不同圾叼,WINDOW_LAYER_MULTIPLIER這個(gè)值從Android2.3版本就是等于5蛤克,所以這里WINDOW_LAYER_MULTIPLIER為5并沒(méi)有什么特殊的含義扔仓。

3、Layer值為何乘以1萬(wàn)以后為什么還要加上1000?

窗口在打開(kāi)或者關(guān)閉的時(shí)候咖耘,為了不那么突兀,都會(huì)設(shè)置一個(gè)動(dòng)畫(huà)撬码,

 /** Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above
    * or below others in the same layer. */
   static final int TYPE_LAYER_OFFSET = 1000;

public void setAnimation(Animation anim, int width, int height, boolean skipFirstFrame,
           int stackClip) {
      ....
       animation = anim;
 // 獲得zorder類(lèi)型,這個(gè)類(lèi)型是通過(guò)Animaion.java的setZAdjustment設(shè)置的
       int zorder = anim.getZAdjustment();
       int adj = 0;
      // ZORDER_TOP則會(huì)+1000儿倒,ZORDER_BOTTOM則會(huì)-1000
       if (zorder == Animation.ZORDER_TOP) {
           adj = TYPE_LAYER_OFFSET;
       } else if (zorder == Animation.ZORDER_BOTTOM) {
           adj = -TYPE_LAYER_OFFSET;
       }

       if (animLayerAdjustment != adj) {
           animLayerAdjustment = adj;
           updateLayers();
       }
    ....
   }

所以Z序號(hào)設(shè)置1000的偏移量就是為了這個(gè)動(dòng)畫(huà)層級(jí)屬性預(yù)留的空間。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末呜笑,一起剝皮案震驚了整個(gè)濱河市夫否,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌叫胁,老刑警劉巖凰慈,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異驼鹅,居然都是意外死亡微谓,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)输钩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)豺型,“玉大人,你說(shuō)我怎么就攤上這事买乃∫霭保” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵剪验,是天一觀的道長(zhǎng)肴焊。 經(jīng)常有香客問(wèn)我,道長(zhǎng)功戚,這世上最難降的妖魔是什么娶眷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮疫铜,結(jié)果婚禮上茂浮,老公的妹妹穿的比我還像新娘。我一直安慰自己壳咕,他們只是感情好席揽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著谓厘,像睡著了一般幌羞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上竟稳,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天属桦,我揣著相機(jī)與錄音熊痴,去河邊找鬼。 笑死聂宾,一個(gè)胖子當(dāng)著我的面吹牛果善,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播系谐,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼巾陕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了纪他?” 一聲冷哼從身側(cè)響起鄙煤,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎茶袒,沒(méi)想到半個(gè)月后梯刚,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡薪寓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年亡资,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片向叉。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沟于,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出植康,到底是詐尸還是另有隱情旷太,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布销睁,位于F島的核電站供璧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏冻记。R本人自食惡果不足惜睡毒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望冗栗。 院中可真熱鬧演顾,春花似錦、人聲如沸隅居。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)胎源。三九已至棉钧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涕蚤,已是汗流浹背宪卿。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工的诵, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人佑钾。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓西疤,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親休溶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瘪阁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

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