「Jetpack - Lifecycle梳理」

「Jetpack - Lifecycle梳理」

一、寫在前面

谷歌推出Jetpack系列已經(jīng)有一段時間了,作為AAC(Android Architecture Components)架構(gòu)組件基礎(chǔ),使開發(fā)的過程越來越規(guī)范化嗅回,遵循谷歌推薦的最佳做法不僅使App更加健壯;體驗更優(yōu)。代碼層面更加簡潔(Jetpack內(nèi)部幫我們處理了很多)優(yōu)雅暗膜,消除了冗余的樣板代碼。

關(guān)于Jetpack系列的解析鞭衩,大佬們輸出了很多優(yōu)秀的文章学搜。學(xué)到了很多,這里還是自己系統(tǒng)的梳理一遍论衍,構(gòu)建自己的知識體系瑞佩,包括LiveData、ViewModel坯台、Room炬丸、WorkManager、Paging3蜒蕾、Compose等等稠炬。

二焕阿、Lifecycle是什么?

官方定義

用于生命周期感應(yīng)型組件的構(gòu)建酸纲,可以根據(jù)Fragment捣鲸、Activity的生命周期狀態(tài)而自動調(diào)整自身的行為、操作

  • Lifecycle是一個抽象類闽坡,用于存儲有關(guān)組件(Activity栽惶、Fragment)的生命周期狀態(tài)的信息,并允許其他對象觀察此狀態(tài)疾嗅。
  • 使用兩種主要的枚舉跟蹤相關(guān)組件的生命周期狀態(tài)

事件Events

  • 從框架和Lifecycle類分派的生命周期事件外厂。這些事件映射到 Activity 和 Fragment 中的回調(diào)事件。

狀態(tài)States

  • Lifecycle 對象跟蹤的組件的當(dāng)前狀態(tài)代承。
  • 官網(wǎng)的結(jié)構(gòu)圖


    states.png
三汁蝶、使用依賴

(早期的依賴已經(jīng)棄用了)
lifecycle-extensions 中的 API 已棄用。您可以為特定 Lifecycle 工件添加所需的依賴項论悴。
添加相關(guān)組件的依賴

dependencies {
  val lifecycle_version = "2.4.0"
  //without ViewModel or LiveData
  implementation("androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version")
  //ViewModel(可選的)
  implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version")
  // LiveData(可選的)
  implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version")
}

一般的使用Lifecycle都會搭配ViewModel掖棉、LiveData一起使用,構(gòu)建數(shù)據(jù)驅(qū)動UI型應(yīng)用膀估,可以說Lifecycle作為Jetpack的基石幔亥,循序漸進(jìn)的去掌握有助于理解深刻。

四察纯、生命周期的管理
  • 生命周期的管理很重要

Android中的內(nèi)存泄漏問題很大一部分來源于對生命周期的管理不當(dāng)帕棉,資源在本應(yīng)該釋放的時候并沒有得到釋放。導(dǎo)致生命周期短的組件持有了生命周期長的組件最終導(dǎo)致內(nèi)存泄漏饼记,應(yīng)用Crash香伴。自定義View包含動畫時,onPause時動畫的暫停具则,handler回收消息的移除等這些都與生命周期關(guān)聯(lián)即纲。

  • 官方的使用Demo(獲取定位信息)

在App啟動時開啟獲得定位的信息對應(yīng)onStart(),而在onStop()對資源進(jìn)行釋放博肋。

internal class MyLocationListener(
  private val context: Context,
  private val callback: (Location) -> Unit
) {
  fun start() {
    //連接到定位服務(wù)器低斋,connect to system location service
  }
  fun stop() {
    //斷開與服務(wù)器的鏈接,disconnect from system location service
  }
}

class MyActivity : AppCompatActivity() {
  private lateinit var myLocationListener: MyLocationListener
  override fun onCreate(...) {
    myLocationListener = MyLocationListener(this) { location ->
    //update ui
   }
  }
  
  public override fun onStart() {
    super.onStart()
    myLocationListener.start()
  }
  
  public override fun onStop() {
    super.onStop()
    myLocationListener.stop()
  }
}

Demo的實現(xiàn)很簡單束昵,但是具有代表性拔稳,比較符合我們以往的“開發(fā)習(xí)慣”葛峻,雖然做到了對生命周期的管理锹雏,在合適的做到了資源的使用與釋放,但是其實是存在問題的术奖。

1.太過于理想化-無論是在onStart()還是在onStop()礁遵,我們都是基于App的生命能夠正常的執(zhí)行的前提之下轻绞,并沒有考慮到異常的情況下如何管理資源;建立在假設(shè)它們能順利執(zhí)行佣耐,對組件MyLocationListener生命周期的管理太過于脆弱政勃。

2.一個完整的App肯定包含的組件很多,忽略了其他組件的條件競爭關(guān)系兼砖,其次隨之系統(tǒng)的不斷迭代奸远,方法的疊加,項目會不容易管理就單生命周期這一項工作就很難處理完美讽挟。

3.思考-Glide都不陌生懒叛,在調(diào)用的時候只需要傳入this,內(nèi)部維護(hù)了一套生命周期管理流程耽梅,那么如果MyLocationListener綁定到MyActivity之上這個問題不就解決了嘛薛窥?Lifecycle解決了這個問題支示。

五舵盈、Lifecycle源碼實現(xiàn)
1.Lifecycle

<font color = #0000FF>Defines an object that has an Android Lifecycle. Fragment and FragmentActivity classes implement LifecycleOwner interface which has the getLifecycle method to access the Lifecycle. You can also implement LifecycleOwner in your own classes.</font>

<font color = #0000FF>Lifecycle.Event.ON_CREATE, Lifecycle.Event.ON_START, Lifecycle.Event.ON_RESUME events in this class are dispatched after the LifecycleOwner's related method returns. Lifecycle.Event.ON_PAUSE, Lifecycle.Event.ON_STOP, Lifecycle.Event.ON_DESTROY events in this class are dispatched before the LifecycleOwner's related method is called. For instance, Lifecycle.Event.ON_START will be dispatched after onStart returns, Lifecycle.Event.ON_STOP will be dispatched before onStop is called. This gives you certain guarantees on which state the owner is in.</font>

<font color = #0000FF>To observe lifecycle events call addObserver(LifecycleObserver) passing an object that implements either DefaultLifecycleObserver or LifecycleEventObserver.</font>

簡單的概括一下:定義一個具有生命周期的對象。FragmentFragmentActivity實現(xiàn)了LifecycleOwner接口掐松,而接口中方法getLifecycle可以獲得Lifecycle引用众旗,開發(fā)者可以通過實現(xiàn)LifecycleOwner接口來自定義自己的生命周期組件罢杉,通過類中狀態(tài),如Lifecycle.Event.ON_START等完成對應(yīng)的匹配逝钥,要觀察生命周期的事件那么需要通過添加生命周期的觀察者addObserver(LifecycleObserver)傳遞的是DefaultLifecycleObserver或者LifecycleEventObserver的實現(xiàn)類屑那。

  • 注釋中解釋的很清楚,Lifecycle相當(dāng)于一個中轉(zhuǎn)站艘款,有什么作用呢持际?管理生命周期的組件,無論是系統(tǒng)的Fragment哗咆、Activity或者是開發(fā)自定義的組件(實現(xiàn)了LifecycleOwner接口)蜘欲。當(dāng)狀態(tài)流轉(zhuǎn)時,“中轉(zhuǎn)站”內(nèi)的組件的生命周期狀態(tài)應(yīng)該保持對應(yīng)晌柬±逊荩看看源碼中幾個重要的方法:
public abstract class Lifecycle {
  @MainThread
  public abstract void addObserver(@NonNull LifecycleObserver observer);
  
  @MainThread
  public abstract void removeObserver(@NonNull LifecycleObserver observer);
  
  @MainThread
  @NonNull
  public abstract State getCurrentState();
  
  public enum Event {
    ON_CREATE,ON_START,ON_PAUSE,ON_STOP,ON_DESTROY,ON_ANY;
    
    @Nullable
    public static Event downFrom(@NonNull State state) {
      switch (state) {
          case CREATED:
            return ON_DESTROY;
          case STARTED:
            return ON_STOP;
          case RESUMED:
            return ON_PAUSE;
      }
    }
    //......
  }
  public enum State {
    DESTROYED,INITIALIZED,CREATED,STARTED,RESUMED;
    public boolean isAtLeast(@NonNull State state) {
      return compareTo(state) >= 0;
    }
  }
}
  • 由之前給出的圖,Lifecycle中定義了狀態(tài)State與之對應(yīng)的事件Event年碘,將綁定的生命周期組件添加到中轉(zhuǎn)站之中澈歉,隨著狀態(tài)主體LifecycleOwner狀態(tài)的改變而獲得對應(yīng)的狀態(tài)-addObserver();同樣的有添加就有移除操作removeObserver()屿衅。也就是說Owner的狀態(tài)發(fā)生改變需要搭配LifecycleObserver才能被轉(zhuǎn)發(fā)下去埃难,典型的觀察與訂閱,首先不看LifecycleObserver具體實現(xiàn)。Lifecycle作為抽象類涡尘,看看其具體實現(xiàn)類忍弛。
  • LifecycleRegistry實現(xiàn)類

Lifecycle的具體實現(xiàn)類,用來處理多個LifecycleObserver的狀態(tài)考抄,同時除了Fragment與Activity以外细疚,還可以處理自定義的生命周期組件〈罚看看是如何處理生命周期事件傳遞的疯兼。

public class LifecycleRegistry extends Lifecycle {
  //通過一個FastSafeIterableMap將觀察者連同狀態(tài)一起保存起來,保存調(diào)用addObserver()后存儲的對象贫途,這個map
  //系統(tǒng)自定義的結(jié)構(gòu)镇防,線程不安全,但是提供了在遍歷時修改的功能潮饱。
  private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap = 
    new FastSafeIterableMap<>();
  //當(dāng)前的狀態(tài)
  private State mState;
  //若引用持用了生命周期的組件
  private final WeakReference<LifecycleOwner> mLifecycleOwner;
  
  private LifecycleRegistry(@NonNull LifecycleOwner provider, boolean enforceMainThread) {
    mLifecycleOwner = new WeakReference<>(provider);
    mState = INITIALIZED;
    mEnforceMainThread = enforceMainThread;
  }
  //設(shè)置當(dāng)前狀態(tài)
  @MainThread
  public void setCurrentState(@NonNull State state) {
    moveToState(state);
  }
  //處理生命周期事件
  public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
    moveToState(event.getTargetState());
  }
  
  private void moveToState(State next) {
    if (mState == next) {
      return;
    }
    mState = next;
    if (mHandlingEvent || mAddingObserverCounter != 0) {
      mNewEventOccurred = true;
      return;
    }
    mHandlingEvent = true;
    sync();
    mHandlingEvent = false;
  }
  
  private boolean isSynced() {
    if (mObserverMap.size() == 0) {
            return true;
    }
    State eldestObserverState = mObserverMap.eldest().getValue().mState;
    State newestObserverState = mObserverMap.newest().getValue().mState;
    return eldestObserverState == newestObserverState && mState == newestObserverState;
  }
  
  private void sync() {
    //省略判空
    while (!isSynced()) {
      mNewEventOccurred = false;
      if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
        backwardPass(lifecycleOwner);
      }
       Map.Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
         if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass(lifecycleOwner);
      }
    }
    mNewEventOccurred = false;
  }
  
  private void forwardPass(LifecycleOwner lifecycleOwner) {
    //....
    observer.dispatchEvent(lifecycleOwner, event);
    //....
  }
  
  private void backwardPass(LifecycleOwner lifecycleOwner) {
    //...
    observer.dispatchEvent(lifecycleOwner, event);
    //...
  }
  
  static class ObserverWithState {
    State mState;
    LifecycleEventObserver mLifecycleObserver;
    ObserverWithState(LifecycleObserver observer, State initialState) {
      mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
      mState = initialState;
    }
    void dispatchEvent(LifecycleOwner owner, Event event) {
      State newState = event.getTargetState();
      mState = min(mState, newState);
      mLifecycleObserver.onStateChanged(owner, event);
      mState = newState;
    }
  }
}

1.在構(gòu)造函數(shù)中来氧,可以看到提供了一個類型為LifecycleOwner的provider,這個很好理解香拉,結(jié)合方法addObserver()啦扬,一個宿主Owner組件中可以包含多個依附的組件,依賴于Owner的生命周期凫碌。只需要觀察這個Owner的狀態(tài)變更作出自身的操作即可扑毡,也即是添加觀察者Observer(LifecycleObserver)。

2.在方法sync()中盛险,首先對目標(biāo)狀態(tài)與當(dāng)前狀態(tài)作了比較瞄摊,方法isSynced(),判斷當(dāng)前狀態(tài)與目標(biāo)是否相等苦掘,并且最新狀態(tài)與最舊的狀態(tài)是否一致换帜,如果都滿足,那么就不會在處理鹤啡。

3.while(!isSynced())中惯驼,也即是狀態(tài)同步,將當(dāng)前狀態(tài)分別與最新递瑰、最舊的狀態(tài)比較保證觀察者的狀態(tài)都是一致的祟牲,如果當(dāng)前狀態(tài)比最舊的狀態(tài)小那么走backwardPass(),反之當(dāng)前狀態(tài)比最新的狀態(tài)大走forwardPass()抖部。以Activity為例说贝,從onStartonResume經(jīng)歷的事件是很短暫的,這也是為什么取當(dāng)前狀態(tài)的下移狀態(tài)慎颗。

//Returns the Lifecycle.Event that will be reported by a Lifecycle leaving the specified //Lifecycle.State to a higher state, or null if there is no valid event that can move up //from the given state.
public static Event upFrom(@NonNull State state) {
  switch (state) {
     case INITIALIZED:
         return ON_CREATE;
     case CREATED:
         return ON_START;
     case STARTED:
         return ON_RESUME;
     default:
         return null;
  }
}
  • dispatchEvent

無論是backwardPass還是forwardPass乡恕,最終都會執(zhí)行到dispatchEvent方法换淆,getTargetState通過計算對應(yīng)的狀態(tài),通知到所有的觀察者几颜。而繼承自LifecycleObserverLifecycleEventObserver接口方法onStateChanged就完成了狀態(tài)的更新操作。

2.LifecycleOwner

<font color = #0000FF>A class that has an Android lifecycle. These events can be used by custom components to handle lifecycle changes without implementing any code inside the Activity or the Fragment.</font>

具有Android生命周期的類讯屈,通過事件自定義的組件可以處理生命周期的變化而無需在Activity或Fragment中實現(xiàn)相關(guān)代碼蛋哭。

LifecycleOwner是一個接口,僅僅包含了一個方法涮母。返回“生命周期”Lifecycle谆趾。

@SuppressWarnings({"WeakerAccess", "unused"})
public interface LifecycleOwner {
  @NonNull
  Lifecycle getLifecycle();
  //The lifecycle of the provider.
}

既然是接口,那么看看實現(xiàn)類叛本,以AppCompatActivity為例沪蓬,而其完整的繼承鏈路為:

AppCompatActivity -> FragmentActivity -> ComponentActivity

直接查看ComponentActivity的實現(xiàn)細(xì)節(jié),看看究竟是如何管理生命周期的来候。

public class ComponentActivity extends androidx.core.app.ComponentActivity implements LifecycleOwner... {
  
  private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
  
  @NonNull
  @Override
  public Lifecycle getLifecycle() {
    return mLifecycleRegistry;
  }
  
  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
     // Restore the Saved State first so that it is available to
     // OnContextAvailableListener instances
     mSavedStateRegistryController.performRestore(savedInstanceState);
     mContextAwareHelper.dispatchOnContextAvailable(this);
     super.onCreate(savedInstanceState);
     //ReportFragment注入
     ReportFragment.injectIfNeededIn(this);
     if (mContentLayoutId != 0) {
       setContentView(mContentLayoutId);
     }
   }
}

ComponentActivity中僅僅只有一個生命周期方法onCreate()作了處理跷叉,而其他的生命周期方法并未有具體實現(xiàn)。那又是怎么管理生命周期的呢营搅?跟預(yù)期顯然是不符合的云挟,但是注意到這個ReportFragment這個的注入。似曾相識转质,如果熟悉Glide圖片加載庫對生命周期的管理-無布局的Fragment注入园欣。這里其實也做了同樣的事情⌒菪罚看看是不是使用相似的方法來管理生命周期沸枯。

  • ReportFragment

ReportFragment關(guān)鍵代碼實現(xiàn)。

public class ReportFragment extends Fragment {
  public static void injectIfNeededIn(Activity activity) {
    if (Build.VERSION.SDK_INT >= 29) {
      activity.registerActivityLifecycleCallbacks(new LifecycleCallbacks()));
    }
    android.app.FragmentManager manager = activity.getFragmentManager();
    if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
      manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
      manager.executePendingTransactions();
    }
  }
  
  //....
  static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) {
    if (activity instanceof LifecycleRegistryOwner) {
       ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
       return;
    }
    if (activity instanceof LifecycleOwner) {
        Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
        if (lifecycle instanceof LifecycleRegistry) {
        ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
       }
     }
  }
    
  @Override
  public void onStart() {
    super.onStart();
    dispatchStart(mProcessListener);
    dispatch(Lifecycle.Event.ON_START);
  }
  //.....
}

關(guān)鍵方法dispatch()赂弓,ReportFragment通過注入的方法绑榴,依附到Activity之上,根據(jù)Fragment特性盈魁,此時Fragment的生命周期就與宿主Activity綁定了彭沼。對宿主Activity的生命周期的管理自然的就后移到了Fragment之上也就是ReportFragment中。而最終都回調(diào)到了dispatch()之中备埃,到這里就完成了分發(fā)的工作姓惑,那么由誰來真正處理呢?

((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);

之前提到接口Lifecycle的實現(xiàn)類LifecycleRegistry則是完成了對生命周期的處理按脚。

總結(jié)一下:

1.ReportFragment通過注入的方式依附到Activity之上于毙,將自身的生命周期與Activity綁定,也即是將生命周期的管理后移辅搬。

2.通過dispatch()來分發(fā)生命周期事件唯沮。而最終處理生命周期事件的類則為Lifecycle的實現(xiàn)類-LifecycleRegistry

  • 自定義生命周期感知類

官方比較推薦的做法是實現(xiàn)DefaultLifecycleObserver接口

class MyObserver : DefaultLifecycleObserver {
    override fun onResume(owner: LifecycleOwner) {
        //do something
    }

    override fun onPause(owner: LifecycleOwner) {
        //do something
    }
}

myLifecycleOwner.getLifecycle().addObserver(MyObserver())

當(dāng)然也可以配合LifecycleRegistryLifecycleOwner實現(xiàn)更加細(xì)致的功能需求

class MyActivity : Activity(), LifecycleOwner {

    private lateinit var lifecycleRegistry: LifecycleRegistry

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        lifecycleRegistry = LifecycleRegistry(this)
        lifecycleRegistry.markState(Lifecycle.State.CREATED)
    }

    public override fun onStart() {
        super.onStart()
        lifecycleRegistry.markState(Lifecycle.State.STARTED)
    }

    override fun getLifecycle(): Lifecycle {
        return lifecycleRegistry
    }
}
六脖旱、文檔

Jetpack-Lifecycle

Lifecycle

Modern Android Development

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者介蛉。
  • 序言:七十年代末萌庆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子币旧,更是在濱河造成了極大的恐慌践险,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吹菱,死亡現(xiàn)場離奇詭異巍虫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)鳍刷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進(jìn)店門占遥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人输瓜,你說我怎么就攤上這事瓦胎。” “怎么了尤揣?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵凛捏,是天一觀的道長。 經(jīng)常有香客問我芹缔,道長坯癣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任最欠,我火速辦了婚禮示罗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘芝硬。我一直安慰自己蚜点,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布拌阴。 她就那樣靜靜地躺著绍绘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪迟赃。 梳的紋絲不亂的頭發(fā)上陪拘,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天,我揣著相機(jī)與錄音纤壁,去河邊找鬼左刽。 笑死,一個胖子當(dāng)著我的面吹牛酌媒,可吹牛的內(nèi)容都是我干的欠痴。 我是一名探鬼主播迄靠,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼喇辽!你這毒婦竟也來了掌挚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤菩咨,失蹤者是張志新(化名)和其女友劉穎吠式,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旦委,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年雏亚,在試婚紗的時候發(fā)現(xiàn)自己被綠了缨硝。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡罢低,死狀恐怖查辩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情网持,我是刑警寧澤宜岛,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站功舀,受9級特大地震影響萍倡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜辟汰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一列敲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧帖汞,春花似錦戴而、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至催首,卻和暖如春扶踊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背郎任。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工姻檀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人涝滴。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓绣版,卻偏偏與公主長得像胶台,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子杂抽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評論 2 349

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