JetPack源码解析(一):Lifecycle解析

JetPack作为Google官方推荐的一套标准化开发套件,很值得去使用和学习。

这篇介绍Lifecycle。Lifecycle是这一套控件基石。其他组件都或多或少有用到或者关联到Lifecycle,其作用是构建生命周期感知型组件,对全局的生命周期进行管理。

基本使用

0.依赖(可选)

//本文以当前稳定版本2.2.0展开
def lifecycle_version = "2.2.0"

// Lifecycles only (without ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"

 // alternately - if using Java8, use the following instead of lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

上述添加的是Lifecyclektx扩展包,其本质就是Kotlin 扩展程序,也可以不添加。不过官方将其列为Jetpack 的一部分,这里将其加上。

如果用的是java8官方推荐使用lifecycle-common-java8依赖,这样可以不使用注解方式配置lifecycle

1.继承LifecycleObserver

  • 注解方式(不用lifecycle-common-java8
    class MyObserver : LifecycleObserver {

        @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
        fun connectListener() {
            ...
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        fun disconnectListener() {
            ...
        }
    }

    myLifecycleOwner.getLifecycle().addObserver(MyObserver())
    
  • Java8方式
class MyObserver :DefaultLifecycleObserver{
    override fun onCreate(owner: LifecycleOwner) {

    }

    override fun onResume(owner: LifecycleOwner) {

    }

    override fun onPause(owner: LifecycleOwner) {

    }
}

2.绑定界面

既然MyObserver拥有了感知生命周期的能力,我们在ActivityFragment中注册即可。


lifecycle.addObserver(MyObserver())//Activity

viewLifecycleOwner.lifecycle.addObserver(MyLifecycleObserver(this))//Fragment

源码解析(针对Java8方式)

示例中用到的Lifecycle相关类就这一个DefaultLifecycleObserver,那我们就从它开始顺藤摸瓜。

DefaultLifecycleObserver

DefaultLifecycleObserver是一个接口,里面有生命周期对应的6个方法,继承自FullLifecycleObserver

/**
 * If a class implements both this interface and {@link LifecycleEventObserver}, then
 * methods of {@code DefaultLifecycleObserver} will be called first, and then followed by the call
 * of {@link LifecycleEventObserver#onStateChanged(LifecycleOwner, Lifecycle.Event)}
 * <p>
 *
 * 如果一个类同时继承了该类【DefaultLifecycleObserver】和`LifecycleEventObserver`两个接口,那么该类下的方法会先调用,
 * 然后`LifecycleEventObserver`下的`onStateChanged(LifecycleOwner, Lifecycle.Event)}`方法会被调用。
 
 * If a class implements this interface and in the same time uses {@link OnLifecycleEvent}, then
 * annotations will be ignored.
 */
public interface DefaultLifecycleObserver extends FullLifecycleObserver {
    @Override
    default void onCreate(@NonNull LifecycleOwner owner) { .. }
    
    @Override
    default void onStart(@NonNull LifecycleOwner owner) { .. }
    ...
}

注释说:如果一个类同时继承了该类【DefaultLifecycleObserver】和LifecycleEventObserver两个接口,那么该类下的【DefaultLifecycleObserver】下的方法会先调用,然后LifecycleEventObserver下的onStateChanged(LifecycleOwner, Lifecycle.Event)}方法会被调用。

LifecycleEventObserver是啥?是一个接口,继承LifecycleObserver

YourActivity继承AppCompatActivity继承FragmentActivity继承ComponentActivity,打开ComponentActivity的构造方法,发现它实现了LifecycleOwner接口。

画个总图理解下:

Lifecycle相关接口
Lifecycle相关接口

Lifecycle

注册时候用的方法是lifecycle.addObserver(MyObserver()),其中getLifecycle()方法回调的是个LifecycleRegistry

private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
public Lifecycle getLifecycle() {
    return mLifecycleRegistry;
}

LifecycleRegistry继承LifecycleLifecycle是个抽象类,用于存储有关组件(如 Activity 或 Fragment)的生命周期状态的信息,并允许其他对象观察此状态。

public abstract class Lifecycle {
    
    ...

    @MainThread
    public abstract void addObserver(@NonNull LifecycleObserver observer);

    @MainThread
    public abstract void removeObserver(@NonNull LifecycleObserver observer);

    @MainThread
    public abstract State getCurrentState();

    public enum Event {
    ....
    }

    public enum State {
      ...
    }
}

Lifecycle中持有两个枚举类,EventState:State表示一个一个的状态节点;Event表示一个节点到另一个节点之间所执行的事件。

生命周期状态示意图

addObserver

addObserver就是通过传递观察者的实例来添加观察者addObserver具体的使用还是在LifecycleRegistry中实现的:

@Override
public void addObserver(@NonNull LifecycleObserver observer) {
    
    -----------------------------几个角色纷纷登场,先认识下------------------------------------
    State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
    ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
    ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

    if (previous != null) {
        return;
    }
    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
    if (lifecycleOwner == null) {
        // it is null we should be destroyed. Fallback quickly
        return;
    }

    boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
    
   ---------------------------calculateTargetStates()---------------------------------------------------------- 
    State targetState = calculateTargetState(observer);
    mAddingObserverCounter++;
    while ((statefulObserver.mState.compareTo(targetState) < 0
            && mObserverMap.contains(observer))) {
        pushParentState(statefulObserver.mState);
        statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
        popParentState();
        // mState / subling may have been changed recalculate
        targetState = calculateTargetState(observer);
    }

    if (!isReentrance) {
        // we do sync only on the top level.
        sync();
    }
    mAddingObserverCounter--;
}

LifecycleRegistry构造方法里面初始化了这两个值。

public LifecycleRegistry(@NonNull LifecycleOwner provider) {
    mLifecycleOwner = new WeakReference<>(provider);
    mState = INITIALIZED;
}

addObserver往下看,mState会随着当前生命周期而变化,只要未被销毁,initialState就赋值为INITIALIZED,然后和observer一起合成一个对象保存了起来。然后以observer为KEY,合成的这个对象【ObserverWithState】为VLAUE,放在一个Map中。顺便还把mState

lifecycleOwner是一个弱引用,持有的是个LifecycleOwner对象,其实就是activity/Fragment自己。

这个Map的putIfAbsent方法有点意思,如果Map中原先没有这个Key,就加进去,返回null;有的话返回这一对K,V。那么第一次放进去返回的previous肯定为null了。

isReentrance判断是否是第一次进入。

先认清楚这几个人

上面看不懂没关系,我写的有点乱,咱捋一下,这几个对象先认清:

**mState : ** 当前生命周期所在状态

**statefulObserver ** --- observer :我们传进来的obs

​ --- mState: 属于statefulObserver的状态,不出幺蛾子一定是INITIALIZED

mObserverMap : 一个Map。Key是我们传进来的obs;Value是statefulObserver

lifecycleOwner: 我们调用addObserver时候所在的activity/Fragment。

targetState : calculateTargetState计算返回的一个状态

mParentStates : 一个装在State的List,此时里面啥都没有。

然后看calculateTargetState方法:

calculateTargetState

private ArrayList<State> mParentStates = new ArrayList<>();
private State calculateTargetState(LifecycleObserver observer) {
    //返回oberver对应Entry的上一对Entry
    Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);

    //previous的State
    State siblingState = previous != null ? previous.getValue().mState : null;
    //最后一个parentState的State
    State parentState = !mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() - 1)
            : null;
    return min(min(mState, siblingState), parentState);
}

返回 ①mObserverMap我们传进来的obs的前一个obs的State , ② mParentStates 中最后一个State , ③ mStatus当前生命周期所在State , 这三个状态的最小值。【还是这张图,左为小,右为大】

生命周期状态示意图

虽然翻译出来了,但还是不懂这是要干啥,过。

但我们可以肯定第一次返回的值是mStatus的值,因为第一次mObserverMap没有上一个,mParentStates 里面是空的。

targetState : calculateTargetState计算返回的一个状态,第一次为mState

while循环

跟着一个While循环,主要看statefulObserver.mState.compareTo(targetState) < 0,后面那个判断不出意外恒为true【observer可是上一步刚加进去的】。

只要statefulObserver.mState小于targetState 就一直循环执行执行。

targetState 第一次下来为mState

还是不知道这是想表达什么,那就跟着看循环里面,既然里面有代码肯定会执行。先看dispatchEvent方法。

dispatchEvent

传入的两个值,一个是当前LifecycleOwner,就是activit中传入的自己。另一个是当前状态STATUS对应的下一个事件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 = getStateAfter(event);
        mState = min(mState, newState);
        mLifecycleObserver.onStateChanged(owner, event);
        mState = newState;
    }
}

然后getStateAfter返回经过当前事件后返回的状态;再将这个状态和mStates的最小值传给mStatus。onStateChanged如下:

@Override
public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
    switch (event) {
        case ON_CREATE:
            mFullLifecycleObserver.onCreate(source);
            break;
        case ON_START:
            mFullLifecycleObserver.onStart(source);
            break;
        case ON_RESUME:
            mFullLifecycleObserver.onResume(source);
            break;
        case ON_PAUSE:
            mFullLifecycleObserver.onPause(source);
            break;
        case ON_STOP:
            mFullLifecycleObserver.onStop(source);
            break;
        case ON_DESTROY:
            mFullLifecycleObserver.onDestroy(source);
            break;
        case ON_ANY:
            throw new IllegalArgumentException("ON_ANY must not been send by anybody");
    }
    if (mLifecycleEventObserver != null) {
        mLifecycleEventObserver.onStateChanged(source, event);
    }
}

可以看到其实调用的还是自己的Full生命周期方法,也就是你自定义的Observer中的方法就这样调用了。

再看我上一句加粗的话,证明在dispach方法中,statefulObserver.mStatus是从顺着生命周期一直变化的[从INITIALIZED一直到当前状态]。

那我们回过头去。

再看While循环

dispatchEvent方法中statefulObserver.mStatus的值会顺着生命周期变化的。所以我们现在再看代码就是这个样子:

statefulObserver.mState  =  `INITIALIZED`
 mState  =  当前生命周期所对应的状态
while( statefulObserver.mState 小于  mState ){
    void dispatchEvent(observer){
        observer.mstate的生命周期方法();
        tatefulObserver.mState + 1;
    }.run
}

也就是从INITIALIZED状态起,到当前状态为止,observer中对应生命周期状态的方法将会一一被触发。也就是说,假如你在onResume方法中调用addObserver(YourObserver())方法,YourObserver()中的onCreate、onStart、onResume方法将会依次执行。

R.id.btn5->{
    LifecycleRegistry(this).addObserver(MyObserver())
}
//Result:
//2020-12-16 14:55:34.788 12186-12186/com.cy.transition E/>>MyObserver:: onCreate
//2020-12-16 14:55:34.788 12186-12186/com.cy.transition E/>>MyObserver:: onStart
//2020-12-16 14:55:34.788 12186-12186/com.cy.transition E/>>MyObserver:: onResume

再看calculateTargetState

按照我们以上的推论,calculateTargetState方法中应该直接返回mState就可以了,为什么要返回mState、mObserverMap中前一个obs的state 和 parentState中最后一个State的最小值呢?

这个我也没看懂,网上找到了两种解释,大家可以参考下:

  1. 为了保证列表中后加的 Observer 的状态不能大于前面的, 这样做之后,如果列表第一个和最后一个的状态和 LifecycleRegistry.mState 相等时,就说明状态同步完成了。——Android架构之美-Lifecycle

  2. 当有新的生命周期事件时,需要将 mObserverMap 中的所有观察者都同步到新的同一状态,这个同步过程可能尚未完成,所以新加入的观察者只能先同步到最小状态。注意在 addObserver 方法的 while 循环中,新的观察者每改变一次生命周期,都会调用 calculateTargetState() 重新计算 targetState

    最终的稳定状态下,没有生命周期切换,没有添加新的观察者,mObserverMap 中的所有观察者应该处于同一个生命周期状态。 ——硬核讲解 Jetpack 之 LifeCycle 源码篇

生命周期变化时的回调

看完addObserver的方法我们知道,可以由此完成从INITIALIZED状态到当前状态的所有事件的方法回调,并且会存入到mObserverMap中。但是仅靠这,并不能保证Activity/Fragment发生生命周期变化时会调用Observer的方法。

所以我们有理由推断,一定是在Activity/Fragment 中注入了什么。

一层层往上找,我们会在ComponentActivity中的onCreate方法中找到这样一行代码:

ReportFragment.injectIfNeededIn(this);

进去之后发现这个ReportFragment类别有洞天。没有界面,但实现了所有生命周期的相关方法,并调用了dispatch方法传入相对应Event。

还是先看injectIfNeededIn方法。

public static void injectIfNeededIn(Activity activity) {
    if (Build.VERSION.SDK_INT >= 29) {
        // On API 29+, we can register for the correct Lifecycle callbacks directly
        activity.registerActivityLifecycleCallbacks(
                new LifecycleCallbacks());
    }
    // Prior to API 29 and to maintain compatibility with older versions of
    // ProcessLifecycleOwner (which may not be updated when lifecycle-runtime is updated and
    // need to support activities that don't extend from FragmentActivity from support lib),
    // use a framework fragment to get the correct timing of Lifecycle events
    android.app.FragmentManager manager = activity.getFragmentManager();
    if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
        manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
        // Hopefully, we are the first to make a transaction.
        manager.executePendingTransactions();
    }
}

我们很熟悉的FragmentManager相关方法,也就是把ReportFragment添加到activity中。这样一来,进入activity就会前会先调用到ReportFragment的生命周期,然后再通过dispatch方法将这个事件转到LifecycleRegistry身上。

dispatch

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);
        }
    }
}

handleLifecycleEvent

通过dispatch转发到了LifecycleRegistry身上。moveToState传入的是Event对应的下一个生命周期状态。

public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
    State next = getStateAfter(event);
    moveToState(next);
}

private void moveToState(State next) {
    if (mState == next) {
        return;
    }
    mState = next;
    if (mHandlingEvent || mAddingObserverCounter != 0) {
        mNewEventOccurred = true;
        // we will figure out what to do on upper level.
        return;
    }
    mHandlingEvent = true;
    sync();
    mHandlingEvent = false;
}

moveToState中注意一点,mSate的值是在这里改变的。每当生命周期传递一次Event来的时候,mState在这里跟着改变一次,所以之前说 mState表示当前activity/Fragment所在生命周期 就是在这里体现的。

sync

// happens only on the top of stack (never in reentrance),
// so it doesn't have to take in account parents
private void sync() {
    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
    if (lifecycleOwner == null) {
        throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"
                + "garbage collected. It is too late to change lifecycle state.");
    }
    while (!isSynced()) {
        mNewEventOccurred = false;
        // no need to check eldest for nullability, because isSynced does it for us.
        if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
            backwardPass(lifecycleOwner);
        }
        Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
        if (!mNewEventOccurred && newest != null
                && mState.compareTo(newest.getValue().mState) > 0) {
            forwardPass(lifecycleOwner);
        }
    }
    mNewEventOccurred = false;
}

isSynced

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;
}

这里的isSync方法是通过mObserverMap中第一个obs和最后一个obsmState是否相等来判断的,如果这三个值相等证明已经同步过了,否则就要进行同步sync。

所谓的sync方法,我给大家翻译一下,就是将mObserverMap中的第一个和最后一个元素的状态,分别与mState做比较。若mState状态比最后一个(最小的那个)还小,证明是在回退操作,则backwardPass

比如说mState状态 是CREATE,最后一个obs状态为START。状态从START变为CREATE,证明是在onStop操作,往回退。

backwardPass
private void backwardPass(LifecycleOwner lifecycleOwner) {
    Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
            mObserverMap.descendingIterator();
    while (descendingIterator.hasNext() && !mNewEventOccurred) {
        Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next();
        ObserverWithState observer = entry.getValue();
        while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) {
            Event event = downEvent(observer.mState);
            pushParentState(getStateAfter(event));
            observer.dispatchEvent(lifecycleOwner, event);
            popParentState();
        }
    }
}

--------------------dispatchEvent之前贴过了,再贴一下,免得往回看-----------------
  static class ObserverWithState{
      ...
        void dispatchEvent(LifecycleOwner owner, Event event) {
            State newState = getStateAfter(event);
            mState = min(mState, newState);
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }
  }

这里面就是将mObserverMap元素遍历出来,通过downEvent获取这个回退的下一个状态,然后在dispatchEvent中将事件分发出去,咱们的obs中就有了相应的回调。ObserverWithState.mState = newState = etStateAfter(event);这里obs中的状态发生了改变,跳到了对应的下一个。

forwardPass
private void forwardPass(LifecycleOwner lifecycleOwner) {
    Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
            mObserverMap.iteratorWithAdditions();
    while (ascendingIterator.hasNext() && !mNewEventOccurred) {
        Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next();
        ObserverWithState observer = entry.getValue();
        ----------------------------不同1,这里是小于0-----------------------------
        while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) {
        ---------------------------不同2,downEvent 改成了UpEvent,在下面第二行--------------------------
            pushParentState(observer.mState);
            observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState));
            popParentState();
        }
    }
}

forwardPass也是同理,可以看到就两点不同,1.判断之前改成了之后;2.downEvent 改成了UpEvent

里面执行的还是遍历出map,然后分发,然后obs.state改为其对应的下一个。


总结

至此,Lifecycle的流程就走完了。最后画个图总结下:

以Activity启动时生命周期变化为例

每次Activity/Fragment发生生命周期变化的时候,mState最先随着界面生命周期变化而变化(moveToState())。然后判断是否同步,即图中所有点是不是在一条垂直线上(isSync),若不在则进行同步:

判断mState在obs们的生命周期之前还是之后,之前则证明是界面在回退;之后则证明界面在创建;

此时以之后(界面创建)为例:

遍历mObserverMap,让每个obs都状态值都改变为下一个,同时发送相应事件回调(onStateChanged),直到它们都和mState在同一垂直线上为止。

最后每个obs的对应事件都会被执行一次了。

最后说明,这幅图表示一个Activity变化时,其内部状态变化示意图。每个Activity内部都会有一个ObserverMap,管理着多个obs。

每次A/B状态变更,其内部obs状态和上图一样的变化
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容