深入理解Activity启动模式

1.前言

  • 启动模式在面试中经常被问到,实际开发中应用广泛,所以是必须掌握的一种技能
  • 下面,我将详细介绍启动模式的相关知识,希望你们会喜欢
  • 第一篇文章,若有纰漏,欢迎指出,必改

2.目录

  • Activity启动模式

  • ActivityStack,TaskRecord,ActivityRecord,Activity关系

  • taskAffinity

  • allowTaskReparenting

  • 实例

  • 总结

3.Activity启动模式

3.1 standard(标准模式)

  • 不复用Activity,startActivity会启动一个新的Activity实例并且置于栈顶,即使栈内已经有这个Activity实例
  • 举例:
    当前Activity栈已经存在ABC三个Activity,需要新启动C,则Activity栈变成ABCC,并不会对原来的C进行复用

3.2 singleTop(栈顶复用模式)

  • 栈顶复用,startActivity启动一个新的Activity时,当前栈顶已经存在这个Activity实例,不会启动新的Actiivty,直接复用当前栈顶Activity,并且回调Activity.onNewIntent方法,如果栈内已有这个Activity但是不在栈顶,则不复用直接启动一个新的Activity实例
  • 举例:
    1. 当前Activity栈已经存在ABC三个Activity,需要新启动D(singleTop),则Activity栈变成ABCD
    2. 当前Activity栈已经存在ABC三个Activity,需要新启动C(singleTop),则Activity栈还是ABC,C被复用并且回调了C的onNewIntent方法
    3. 当前Activity栈已经存在ABC三个Activity,需要新启动B(singleTop),则Activity栈变成ABCB,不会对B进行复用

3.3 singleTask(栈内复用模式)

  • 栈内复用,startActivity启动一个新的Activity时,当前栈内已经存在这个Activity实例,不会启动新的Actiivty,直接复用当前栈内Activity,将这个Activity之上的Activity出栈,并且回调Activity.onNewIntent方法
  • 举例:
    0. 前提是taskAffinity相同
    1. 当前Activity栈已经存在ABC三个activity,需要新启动D(singleTask),则Activity栈变成ABCD
    2. 当前Activity栈已经存在ABC三个activity,需要新启动C(singleTask),则Activity栈还是ABC,C被复用并且回调了C的onNewIntent方法
    3. 当前Activity栈已经存在ABC三个activity,需要新启动B(singleTask),则Activity栈变成AB,B被复用并且回调了B的onNewIntent方法,C被出栈(也就是执行了onPause,onStop,onDestory生命周期)

3.4 singleInstance(单例模式)

  • 不复用Activity,startActivity会启动一个新的Activity栈并且启动一个新的Activity实例,也就是一个栈内有且仅有一个Activity实例
  • 举例:
    当前Activity栈已经存在ABC三个activity,需要新启动D(singleInstance),则新建Activity栈,并将D放入新的Activity栈

4 ActivityStack,TaskRecord,ActivityRecord,Activity关系

  • 4.1 源码

package android.content.pm;
public class ActivityInfo extends ComponentInfo implements Parcelable {
     ...//省略无关代码
    public String taskAffinity;
    ...//省略无关代码
    }
package com.android.server.wm;
/**
 * An entry in the history stack, representing an activity.
 *历史堆栈中的一个条目,代表Activity
 */
final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener {
    ...//省略无关代码
    // activity info provided by developer in AndroidManifest
     final ActivityInfo info; 
    ...//省略无关代码
    }
package com.android.server.wm;
class Task extends WindowContainer<WindowContainer> {
     ...//省略无关代码
      // The affinity name for this task, or null; may change identity.
      String affinity;       
      /** ActivityRecords that are exiting, but still on screen for animations. */
      final ArrayList<ActivityRecord> mExitingActivities = new ArrayList<>();
    ...//省略无关代码
    }
package com.android.server.wm;
/**
 * State and management of a single stack of activities.
 * 负责一个activity栈的状态和管理
 */
class ActivityStack extends Task {
     ...//省略无关代码
      // The affinity name for this task, or null; may change identity.
      String affinity;       
      /** ActivityRecords that are exiting, but still on screen for animations. */
      final ArrayList<ActivityRecord> mExitingActivities = new ArrayList<>();
    ...//省略无关代码
    }
package com.android.server.wm;
/**
 * State and management of a single stack of activities.
 * 负责一个activity栈的状态和管理
 */
class RecentTasks {
     ...//省略无关代码
    // List of all active recent tasks
    private final ArrayList<Task> mTasks = new ArrayList<>();
    /** The non-empty tasks that are removed from recent tasks (see {@link #removeForAddTask}). */
    private final ArrayList<Task> mHiddenTasks = new ArrayList<>();
    ...//省略无关代码
    }
  • 4.2 源码分析

    • ActivityInfo拥有taskAffinity属性,也就是说每个Activity都有taskAffinity属性
    • ActivityRecord持有一个ActivityInfo对象,也就是说一个ActivityRecord对应一个Activity
    • Task拥有taskAffinity属性,也就是说Task对应一种taskAffinity。同时Task持有一个ActivityRecord列表,也就是说一个Task对应多个ActivityRecord
    • ActivityStack继承自Task,与Task具有同样的功能和属性,负责ActivityRecord || Activity栈的状态和管理,一个ActivityStack对应一个Task对应多个ActivityRecord
    • RecentTasks持有Task列表,也就是我们常见的最近任务列表
  • 4.3 关系图

    image.png

5 taskAffinity

  • 5.1 源码

//package android.content.pm;
public class ActivityInfo extends ComponentInfo implements Parcelable {
     ...//省略无关代码
    /**
     * The affinity this activity has for another task in the system.  The
     * string here is the name of the task, often the package name of the
     * overall package.  If null, the activity has no affinity.  Set from the
     * {@link android.R.attr#taskAffinity} attribute.
     * 大概翻译一下,该属性表明任务相关性,默认是应用包名
     */
    public String taskAffinity;
    ...//省略无关代码
    }
//package android.content.pm;
public class ApplicationInfo extends PackageItemInfo implements Parcelable {
     ...//省略无关代码
    /**
     * Default task affinity of all activities in this application.
     * 当前应用所有activity的默认taskAffinity
     */
    public String taskAffinity;
    ...//省略无关代码
    }
  • 5.2 概念

    • 物以类聚,人以群分,该属性表明Activity之间的相关性
    • ApplicationInfo.taskAffinity默认是包名(com.xxx.xxx)
    • 当前应用的Activity.taskAffinity默认是ApplicationInfo.taskAffinity
    • 该属性主要和SingleTask启动模式或者allowTaskReparenting属性配对使用

6 allowTaskReparenting

  • 6.1 源码

//package android.content.pm;
public class ActivityInfo extends ComponentInfo implements Parcelable {
     ...//省略无关代码
    /**
     * Bit in {@link #flags} that indicates that the activity can be moved
     * between tasks based on its task affinity.  Set from the
     * {@link android.R.attr#allowTaskReparenting} attribute.
     * 不同Task之间的Activity可以移动,依赖于taskAffinity属性
     */
    public static final int FLAG_ALLOW_TASK_REPARENTING = 0x0040;
    ...//省略无关代码
    }
  • 6.2 概念

    • 一个flag
    • allowTaskReparenting设置为true代表该Activity可以在ActivityStack/Task之间移动
    • 需要和taskAffinity属性配对使用
  • 6.3 举例

    • 路上捡了流浪狗狗,回家养了几天,如果狗狗是原主人抛弃的(allowTaskReparenting = false),这个狗狗就属于你了,如果狗狗是原主人依然需要的( allowTaskReparenting = true),这个狗狗得还别人。
    • 应用A启动应用B的ActivityC,ActivityC的allowTaskReparenting 设置为true,点击Home键返回桌面,点击应用B,会发现启动的并不是应用B的主Activity,而是ActivityC,此时在ActivityC点击返回键,页面会回退到应用B的主Activity。先记住结论,后面会有实验验证

7 实例

  • 7.1 前言

    • 上面的知识点记住了吗?那开始做题吧
    • Standard启动模式受taskAffinity影响吗?
    • SingleTop启动模式受taskAffinity影响吗?
    • SingleTask启动模式与taskAffinity关系是怎样的?
    • SingleInstance与taskAffinity有什么关联?
    • allowTaskReparenting作用是什么?
    • Activity之间的回退栈逻辑是什么?
    • ...
  • 7.2 探究Standard与taskAffinity的关系

  • 7.2.1 代码

open class BaseActivity : AppCompatActivity() {
    val tag: String = "qwq"
    open lateinit var tv:TextView
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        tv = findViewById<TextView>(R.id.tv)
        tv.text = this.localClassName
        Log.i(tag,"${this.localClassName}任务id:$taskId")
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        Log.i(tag, "${this.localClassName}onNewIntent被调用,接收到传递的数据:${intent?.getStringExtra("data")}");
    }
}
class FirstActivity : BaseActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        tv.setOnClickListener {
            val intent = Intent(this, SecondActivity::class.java)
            intent.putExtra("data", "${this.localClassName}传递的数据")
            startActivity(intent)
        }
    }
}
class SecondActivity : BaseActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        tv.setOnClickListener {
            val intent = Intent(this, ThirdActivity::class.java)
            intent.putExtra("data", "${this.localClassName}传递的数据")
            startActivity(intent)
        }
    }
}
<activity
     android:name=".FirstActivity"
     android:taskAffinity="com.xgz.kwa1"
     android:launchMode="standard">
     <intent-filter>
           <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />
     </intent-filter>
</activity>
<activity android:name=".SecondActivity" 
          android:taskAffinity="com.xgz.kwa1"/>
  • 7.2.2结果

日志打印

2021-12-18 03:56:59.245 7436-7436/com.xgz.kwa I/qwq: FirstActivity:onCreate:任务id:43
2021-12-18 03:57:02.521 7436-7436/com.xgz.kwa I/qwq: SecondActivity:onCreate:任务id:43

adb shell dumpsys activity activities 输出

    Running activities (most recent first):
      TaskRecord{97b4e66 #43 A=com.xgz.kwa1 U=0 StackId=1 sz=2}
        Run #1: ActivityRecord{f80978d u0 com.xgz.kwa/.SecondActivity t43}
        Run #0: ActivityRecord{40a33e1 u0 com.xgz.kwa/.FirstActivity t43}
  • 7.2.3 结论

    taskAffinity对Standard启动模式没有影响
  • 7.3 探究SingleTop与taskAffinity的关系

  • 7.3.1 代码

        <activity
            android:name=".FirstActivity"
            android:launchMode="standard"
            android:taskAffinity="com.xgz.kwa1">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".SecondActivity"
            android:launchMode="singleTop"
            android:taskAffinity="com.xgz.kwa2" />
  • 7.3.2结果

日志打印

2021-12-18 04:05:33.818 7752-7752/com.xgz.kwa I/qwq: FirstActivity:onCreate:任务id:45
2021-12-18 04:05:36.684 7752-7752/com.xgz.kwa I/qwq: SecondActivity:onCreate:任务id:45

adb shell dumpsys activity activities 输出

 TaskRecord{f341410 #45 A=com.xgz.kwa1 U=0 StackId=1 sz=2}
        Run #1: ActivityRecord{968b86a u0 com.xgz.kwa/.SecondActivity t45}
        Run #0: ActivityRecord{aef1362 u0 com.xgz.kwa/.FirstActivity t45}
  • 7.3.3 结论

    taskAffinity对SingleTop启动模式没有影响

  • 7.4 探究SingleTask在taskAffinity不同的情况下表现

  • 7.4.1 代码

        <activity
            android:name=".FirstActivity"
            android:launchMode="standard"
            android:taskAffinity="com.xgz.kwa1">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".SecondActivity"
            android:launchMode="singleTask"
            android:taskAffinity="com.xgz.kwa2" />
  • 7.4.2结果

启动SecondActivity日志打印

2021-12-18 04:13:06.458 8071-8071/com.xgz.kwa I/qwq: FirstActivity:onCreate:任务id:48
2021-12-18 04:13:25.430 8071-8071/com.xgz.kwa I/qwq: SecondActivity:onCreate:任务id:49

adb shell dumpsys activity activities 输出

     TaskRecord{cc73108 #49 A=com.xgz.kwa2 U=0 StackId=1 sz=1}
        Run #1: ActivityRecord{8efb19f u0 com.xgz.kwa/.SecondActivity t49}
      TaskRecord{c1e02c6 #48 A=com.xgz.kwa1 U=0 StackId=1 sz=1}
        Run #0: ActivityRecord{9c48ae1 u0 com.xgz.kwa/.FirstActivity t48}

系统最近任务栏视图


系统最近任务栏视图

在SecondActivity页面按下Home键返回桌面,重新点击桌面图标进入应用,会进入FirstActivity(主Activity)而不是SecondActivity

  • 7.4.3 结论

    taskAffinity不同的情况下,启动SingleTask模式的Activity会新开一个任务栈,系统最近任务栏会新开一个栈视图,从桌面返回会返回主Activity所在栈栈顶Activity
  • 7.4.4 其他

  • 7.4.4.1 实验1:
    • 条件:如果A是主Activity,B与A的taskAffinity相等,C与A的taskAffinity不相等。A启动模式Standard,B和C启动模式SingleTask
    • 操作:A启动B,B启动C
    • Q1:此时最近任务有几个任务栈
    • Q2:此时C可以通过返回键返回B吗
    • Q3:此时按下Home键,通过桌面应用图标返回应用会返回哪个Activity
    • A1:两个
    • A2:可以
    • A3:B
  • 7.4.4.2 实验2:
    • 条件:如果A是主Activity,B与A的taskAffinity不相等,C与A的taskAffinity相等。A启动模式Standard,B和C启动模式SingleTask
    • 操作:A启动B,B启动C
    • Q1:此时最近任务有几个任务栈
    • Q2:此时C可以通过返回键返回B吗
    • Q3:此时按下Home键,通过桌面应用图标返回应用会返回哪个Activity
    • Q4:Q3操作回到应用之后,C回退会回退到哪个Activity
    • Q5:Q4操作之后,A启动B,B会回调onNewIntent还是回调onCreate方法
    • A1:两个
    • A2:可以
    • A3:C
    • A4:A
    • A5:onNewIntent
  • 7.4.4.3 实验3:
    • 条件:A是主Activity,C和A的taskAffinity相等,B和D的taskAffinity相等并且和AC不相等。ABCD启动模式均是SingleTask
    • 操作:A启动B,B启动C,C启动D
    • Q1:此时最近任务有几个任务栈
    • Q2:此时D可以通过返回键返回C吗
    • Q3:此时按下Home键,通过桌面应用图标返回应用,会返回哪个Activity
    • Q4:Q3操作回到应用之后,C回退会回退到哪个Activity
    • Q5:Q4操作之后,A启动B,B会回调onNewIntent还是回调onCreate方法
    • Q6:Q3操作回到应用之后,C启动D,D会回调onNewIntent还是onCreate方法
    • Q7:Q6操作之后,D能返回C吗
    • A1:两个
    • A2:不可以,返回栈是D->B->C->A
    • A3:C
    • A4:A
    • A5:onNewIntent
    • A6:onNewIntent
    • A7:不可以,返回栈是D->B->C->A
  • 7.4.3 总结

    • 在启动模式为SingleTask的情况下,具有相同taskAffinity属性的Activity被分配在同一ActivityStack中
    • 如果这个ActivityStack不存在则新建一个ActivityStack并将Actiivty入栈
    • 每个ActivityStack对应一个最近任务栏视图
    • 一个应用可能存在多个ActivityStack
    • 在没有按下Home键的情况下回退栈按ActivityStack顺序返回,ActivityStack内部按照Activity顺序返回
    • 从桌面返回后,显示Activity为主Activity所在ActivityStack栈顶Activity,回退栈只会根据主Activity所在任务栈进行返回
  • 7.5 探究SingleTask在taskAffinity不同的情况下表现

  • 7.5.1 代码

        <activity
            android:name=".FirstActivity"
            android:launchMode="singleInstance"
            android:taskAffinity="com.xgz.kwa1">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".SecondActivity"
            android:launchMode="singleInstance"
            android:taskAffinity="com.xgz.kwa2" />
  • 7.4.2结果

启动SecondActivity日志打印

2021-12-18 05:52:11.259 9985-9985/com.xgz.kwa I/qwq: FirstActivity:onCreate:任务id:90
2021-12-18 05:52:13.838 9985-9985/com.xgz.kwa I/qwq: SecondActivity:onCreate:任务id:91

adb shell dumpsys activity activities 输出

      TaskRecord{5a0a68c #91 A=com.xgz.kwa2 U=0 StackId=1 sz=1}
        Run #1: ActivityRecord{fc6b473 u0 com.xgz.kwa/.SecondActivity t91}
      TaskRecord{3889dea #90 A=com.xgz.kwa1 U=0 StackId=1 sz=1}
        Run #0: ActivityRecord{143e0e7 u0 com.xgz.kwa/.FirstActivity t90}

系统最近任务栏视图


系统最近任务栏视图

在SecondActivity页面按下Home键返回桌面,重新点击桌面图标进入应用,会进入FirstActivity(主Activity)而不是SecondActivity

  • 7.5.3 结论

    taskAffinity不同的情况下,启动SingleInstance模式的Activity会新开一个任务栈,系统最近任务栏会新开一个栈视图,从桌面返回会返回主Activity所在栈栈顶Activity
  • 7.5.4 其他

  • 7.5.4.1 实验1:
    • 条件:如果A是主Activity,B,C与A的taskAffinity相等,A,B,C启动模式均为SingleInstance
    • 操作:A启动B,B启动C
    • Q1:此时最近任务有几个任务栈
    • Q2:此时C可以通过返回键返回B吗
    • Q3:此时按下Home键,通过桌面应用图标返回应用会返回哪个Activity
    • A1:一个
    • A2:可以
    • A3:A
  • 7.5.4.2 实验2:
    • 条件:如果A是主Activity,B与A的taskAffinity相等,A启动模式均为SingleInstance,B启动模式均为SingleTask
    • 操作:A启动B
    • Q1:此时最近任务有几个任务栈
    • Q2:此时B可以通过返回键返回A吗
    • Q3:此时按下Home键,通过桌面应用图标返回应用会返回哪个Activity
    • Q4:Q3操作之后A会回调onNewIntent还是onCreate方法
    • A1:一个
    • A2:可以
    • A3:A
    • A4:onNewIntent
  • 7.5.4.3 实验3:
    • 条件:A是主Activity,AC的taskAffinity相等,BD的taskAffinity相等并且和AC不相等。AC启动模式均是SingleInstance,BD启动模式均是SingleTask
    • 操作:A启动B,B启动C,C启动D
    • Q1:此时最近任务有几个任务栈
    • Q2:此时D可以通过返回键返回C吗
    • Q3:此时按下Home键,通过桌面应用图标返回应用,会返回哪个Activity
    • Q4:Q3操作之后,A会回调onNewIntent还是onCreate方法
    • A1:两个
    • A2:不可以,返回栈是D->B->C->A
    • A3:A
    • A4:onNewIntent
  • 7.5.3 总结

    • 在启动模式为SingleInstance的情况下,一个Activity对应一个ActivityStack
    • 具有相同taskAffinity的Activity在最近任务栏只会显示一个视图
    • 一个最近任务栏可能会对应多个视图
    • 在没有按下Home键的情况下回退栈按ActivityStack顺序返回,ActivityStack内部按照Activity顺序返回
    • 从桌面返回后,显示Activity为主Activity所在ActivityStack栈顶Activity,回退栈只会根据主Activity所在任务栈进行返回
    • 从桌面返回后,如果主Activity启动模式是SingleInstance,会回调onNewIntent方法

8 总结

  • SingleTop和Standard模式不受taskAffinity影响
  • 在SingleTask模式下不同taskAffinity对应不同的ActivityStack,一个ActivityStack对应一个最近任务视图
  • 在SingleTask模式下不同Activity对应不同的ActivityStack,一个具有相同taskAffinity的多个ActivityStack对应一个最近任务视图
  • 任意模式下,在没有按下Home键的情况下,回退栈按ActivityStack顺序返回,ActivityStack内部按照Activity顺序返回
  • 从桌面返回后,显示Activity为主Activity所在ActivityStack栈顶Activity,回退栈只会根据主Activity所在任务栈进行返回
  • 从桌面返回后,如果显示的Activity启动模式是SingleInstance或者SingleTask,会回调onNewIntent方法
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容