Activity你真的非常了解吗?

1. 生命周期

1.1 Dialog弹出时

  • 如果是单纯的创建Dialog,Activity并不会执行生命周期的方法
  • 但是如果是跳转到一个的Activity的话,当然就是按照正常的生命周期来执行
  • 即onPause() -> onCreate() -> OnStart() -> onResume() -> onStop()(看Activity是否全屏)

1.2 横竖屏切换

经常在网上看到的结论如下
  1. 不设置Activity的android:configChanges时,切横屏时会执行一次、切竖屏时会执行两次
  2. 设置Activity的android:configChanges="orientation"时,切横竖屏时只会执行一次
  3. 设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
我的测试结果

不设置Activity的android:configChanges时,
或 设置Activity的android:configChanges="orientation"时,
或 设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行一次方法。

为什么会出现这个问题呢?

Android 3.2(API 级别 13)开始,当设备在纵向和横向之间切换时,“屏幕尺寸”也会发生变化。因此,在开发针对 API 级别 13 或更高版本系统的应用时,若要避免由于设备方向改变而导致运行时重启,则除了"orientation"值以外,您还必须添加 "screenSize"值。即,您必须声明 android:configChanges="orientation|screenSize"。但是,如果您的应用是面向 API 级别 12 或更低版本的系统,则 Activity 始终会自行处理此配置变更(即便是在 Android 3.2 或更高版本的设备上运行,此配置变更也不会重启 Activity)。

结论

1. Android 3.2 (API 级别 13)以前

上面网上的结论

2. 从 Android 3.2 (API级别 13)以后

1. 不设置Activity的android:configChanges时,  
或 设置Activity的android:configChanges="orientation"时,  
或 设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行一次方法。  
2. 配置 android:configChanges="orientation|screenSize",才不会销毁 activity,且只调用 onConfigurationChanged方法。

1.3 不同场景下Activity生命周期的变化过程

  • 启动Activity:onCreate() -> onStart() -> onResume(),Activity进入运行状态
  • 锁屏时:执行onPause()和onStop(),而开屏时则应该执行onRestart() -> onStart() -> onResume()
  • 打开新的Activity B的生命周期:
graph TD 
A[A: onPause] --> B[B: onCreate]
B --> C[B: onStart]
C --> D[B: onResume]
D --> E[A: onStop]
  • Activity B返回生命周期:
graph TD 
A[B: onPause] --> B[A: onRestart]
B --> C[A: onStart]
C --> D[A: onResume]
D --> E[B: onStop]
E --> F[B: onDestroy]

1.4 将一个Activity设置成窗口的样式

只需要给我们的 Activity 配置如下属性即可。
android:theme="@android:style/Theme.Dialog"

1.5 退出已调用多个Activity的Application

通常情况用户退出一个 Activity 只需按返回键,我们写代码想退出 activity 直接调用 finish() 方法就行

  • 发送特定广播
    在需要接受应用时,发送一个特定的广播,每个Activity收到广播后关闭

  • 递归退出
    在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭

  • 记录打开的Activity
    每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。

public class ActivityManagerApplication extends Application {

    private static Map<String,Activity> destoryMap = new HashMap<>();

    private ActivityManagerApplication() {
    }

    /**
     * 添加到销毁队列
     *
     * @param activity 要销毁的activity
     */

    public static void addDestoryActivity(Activity activity,String activityName) {
        destoryMap.put(activityName,activity);
    }
    /**
    *销毁指定Activity
    */
    public static void destoryActivity(String activityName) {
       Set<String> keySet=destoryMap.keySet();
        for (String key:keySet){
            destoryMap.get(key).finish();
        }
    }
}
  • 设置FLAG
    通过 intent 的 flag 来实现 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) 激活一个新的 activity。如果该任务栈中已经有该 Activity , 那么系统会把这个 Activity 上面的所有 Activity 干掉。

1.6 修改Activity进入和退出动画

  1. 通过设置主题样式在styles.xml中编辑代码,添加themes.xml文件:在AndroidManifest.xml中给指定的Activity指定theme。
  2. 覆写 overridePendingTransition 方法:overridePendingTransition(R.anim.fade, R.anim.hold);

1.7 Activity的四种状态

  • running状态: 用户可以点击,activity 处于栈顶状态。

  • paused状态: Activity失去焦点,被一个非全屏的Activity占据或者被一个透明的Activity覆盖,这个状态的Activity并没有销毁,它所有的状态信息和成员变量扔然存在,只是不能够被点击。(内存紧张的情况,这个Activity有可能被回收)

  • stopped状态:
    被另一个Activity完全覆盖,但是它所有的状态信息和成员变量扔然存在(内存紧张时就没了)

  • killed状态:
    这个Activity已经被销毁,其所有的状态信息和成员变量已经不存在了

1.8 如何处理异常退出

  • Activity异常退出的时候, onPause() -> onSaveInstanceState() -> onStop() -> onDestory()
    需要注意的是onSaveInstanceState()方法与onPause() 并没有严格的先后关系,有可能在onPause()之前,也有可能在其后面调用,但会在 onStop()方法之前调用

  • 异常退出后又重新启动该 Activity
    onCreate() -> onStart() -> onRestoreInstanceState() -> onResume()

如果要恢复则要在 onSaveInstanceState() 中进行保存数据并在 onRestoreInstanceState() 中进行恢复
如果是要退出 app 的话就要捕获全局的异常信息,并退出 app
当然个人建议是使用 UncaughtExceotionHandler 来捕获全局异常进行退出 app 的操作,这样会减少之前崩溃所造成的后遗症!

1.9 什么是onNewIntent

1. Activity launchMode为singleTask或者singleInstance

activity A start activity B
activity B start activity A
在第二步被执行后,activityA就会顺序执行 onNewIntent() -> onRestart() -> onStart () -> onResume()

2. Activity launchMode为singleTop singleTask singleInstance

start activity A
activity A start activity A
在第二步被执行后,activity A就会顺序执行onPause() -> onNewIntent() -> onResume()

第一种情况其实是真正的activity被ReStart,第二种情况是activity位于栈顶时被再次Start就会进入onNewIntent

其实理解的简单一点,无论什么模式,只有activity是同一个实例的情况下,intent发生了变化,就会进入onNewIntent中,这个方法的作用也是让你来对旧的intent进行保存,对新的intent进行对应的处理。


2. 启动模式

2.1 启动模式

graph TD
A{launchMode} --> B[standard默认]
A --> C[singleTop]
A --> E[singleTask]
A --> F[singleInstance]
  • Standard模式(默认模式)

    1. 说明:每一次启动一个Activity都会又一次创建一个新的实例入栈,无论这个实例是否存在。

    2. 生命周期:每次创建的实例Activity的生命周期符合典型的情况,它的onCreate()、onStart()、onResume()都会被调用。

    3. 举例:此时Activity栈中有A、B、C三个Activity,此时C处于栈顶,启动模式为Standard模式。若在C Activity中加入点击事件,需要跳转到还有一个同类型的C Activity。结果栈中会有两个C Activity。

  • SingleTop模式(栈顶复用模式)

    1. 说明:分两种处理情况:须要创建的 Activity 已经处于栈顶时,此时会直接复用栈顶的 Activity 。不会再创建新的 Activity ;若须要创建的 Activity 不处于栈顶,此时会又一次创建一个新的 Activity 入栈,同 Standard 模式一样。

    2. 生命周期:若情况一中栈顶的 Activity 被直接复用时,它的 onCreate 、onStart 不会被系统调用,由于它并没有发生改变。可是一个新的方法 onNewIntent 会被回调( Activity 被正常创建时不会回调此方法)。

    3. 举例:此时 Activity 栈中以此有 A 、B 、C 三个 Activity ,此时 C 处于栈顶,启动模式为 SingleTop 模式。情况一:在 C Activity 中加入点击事件,须要跳转到还有一个同类型的 C Activity 。结果是直接复用栈顶的 C Activity。情况二:在 C Activity 中加入点击事件,须要跳转到还有一个 A Activity。结果是创建一个新的 Activity 入栈。成为栈顶。

  • SingleTask模式(栈内复用模式)

    1. 说明:若须要创建的 Activity 已经处于栈中时,此时不会创建新的 Activity ,而是将存在栈中的 Activity 上面的其他 Activity 所有销毁,使它成为栈顶。

    2. 生命周期:同 SingleTop 模式中的情况一同样。仅仅会又一次回调 Activity 中的 onNewIntent 方法

    3. 举例:此时 Activity 栈中以此有 A 、B 、C 三个 Activity 。此时 C 处于栈顶,启动模式为 SingleTask 模式。情况一:在 C Activity 中加入点击事件,须要跳转到还有一个同类型的 C Activity 。结果是直接用栈顶的 C Activity 。情况二:在 C Activity 中加入点击事件,须要跳转到还有一个 A Activity 。结果是将 A Activity 上面的 B 、C 所有销毁,使 A Activity 成为栈顶。

  • SingleInstance模式(单实例模式)

    1. 说明:SingleInstance 比较特殊,是全局单例模式,是一种加强的 SingleTask 模式。它除了具有它所有特性外,还加强了一点:只有一个实例,并且这个实例独立运行在一个 task 中,这个 task 只有这个实例,不允许有别的 Activity 存在。这个经常使用于系统中的应用,比如 Launch 、锁屏键的应用等等,整个系统中仅仅有一个!所以在我们的应用中一般不会用到。了解就可以。

    2. 举例:比方 A Activity 是该模式,启动 A 后。系统会为它创建一个单独的任务栈,由于栈内复用的特性。兴许的请求均不会创建新的 Activity ,除非这个独特的任务栈被系统销毁。

2.2 启动模式的使用方式

  • 静态的指定方法:在 Manifest.xml 中指定 Activity 启动模式

  • 动态代码设置:在 new 一个 Intent 后通过 IntentaddFlags 方法去指定一个启动模式

注意:以上两种方式都能够为Activity指定启动模式,可是二者还是有差别的。

  1. 优先级:Intent设置方式比Manifest设置方式的优先级要高,即以前者为准

  2. 限定范围:第一种方式无法为 Activity 直接指定 FLAG_ACTIVITY_CLEAR_TOP 标识,另外一种方式无法为 Activity 指定 singleInstance 模式。

2.3 启动模式的实际应用场景

这四种模式中的 Standard 模式是最普通的一种,没有什么特别注意。而 SingleInstance 模式是整个系统的单例模式,在我们的应用中一般不会应用到。所以,这里就具体解说 SingleTopSingleTask 模式的运用场景:

  • SingleTask 模式的运用场景

    1. 最常见的应用场景就是保持我们应用开启后仅仅有一个 Activity 的实例。

    2. 最典型的样例就是应用中展示的主页( Home 页)。

    3. 假设用户在主页跳转到其他页面,运行多次操作后想返回到主页,假设不使用 SingleTask 模式,在点击返回的过程中会多次看到主页,这明显就是设计不合理了。

  • SingleTop 模式的运用场景

    1. 假设你在当前的 Activity 中又要启动同类型的 Activity

    2. 此时建议将此类型 Activity 的启动模式指定为 SingleTop ,能够降低Activity的创建,节省内存!

注意:复用 Activity 时的生命周期回调

1. 这里还须要考虑一个 Activity 跳转时携带页面參数的问题。
2. 由于当一个 Activity 设置了 SingleTop 或者 SingleTask 模式后,跳转此 Activity 出现复用原有 Activity 的情况时,此 Activity 的 onCreate 方法将不会再次运行。onCreate 方法仅仅会在第一次创建 Activity 时被运行。
3. 而一般 onCreate 方法中会进行该页面的数据初始化、UI 初始化,假设页面的展示数据无关页面跳转传递的參数,则不必操心此问题
4. 若页面展示的数据就是通过 getInten() 方法来获取,那么问题就会出现:getInten() 获取的一直都是老数据,根本无法接收跳转时传送的新数据!
实例
public class LifecycleActivity extends AppCompatActivity {

    private static final String TAG = "LifecycleActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lifecycle);
       initData();
    }

    private void initData() {
        Intent intent = getIntent();
        name = intent.getStringExtra("NAME");
    }
}
  • 以上代码中的 LifecycleActivity 在配置文件里设置了启动模式是 SingleTop 模式,依据上面启动模式的介绍可得知,当 LifecycleActivity 处于栈顶时。

  • 再次跳转页面到 LifecycleActivity 时会直接复用原有的 Activity ,并且此页面须要展示的数据是从 getIntent() 方法得来,可是 initData() 方法不会再次被调用,此时页面就无法显示新的数据。

  • 当然这样的情况系统早就为我们想过了,这时我们须要另外一个回调 onNewIntent(Intent intent)方法。此方法会传入最新的 intent ,这样我们就能够解决上述问题。这里建议的方法是又一次去 setIntent 。然后又一次去初始化数据和 UI 。代码例如以下所看到的:

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        initData();
        Log.e(TAG, "onNewIntent: ");
    }
  • 这样,在一个页面中能够反复跳转并显示不同的内

2.4 快速启动一个 Activity

这个问题其实也是比较简单的,就是不要在 Activity 的 onCreate() 方法中执行过多繁重的操作,并且在 onPasue() 方法中同样不能做过多的耗时操作。

2.5 启动流程

注意!这里并不是要回答 Activity 的生命周期!

3 分钟看懂 Activity 启动流程

2.6 Activity的Flags

  • FLAG_ACTIVITY_NEW_TASK
    作用是为 Activity 指定 “SingleTask” 启动模式。跟在 AndroidMainfest.xml 指定效果同样。

  • FLAG_ACTIVITY_SINGLE_TOP
    作用是为 Activity 指定 “SingleTop” 启动模式,跟在 AndroidMainfest.xml 指定效果同样。

  • FLAG_ACTIVITY_CLEAN_TOP
    具有此标记位的 Activity ,启动时会将与该 Activity 在同一任务栈的其他 Activity 出栈。一般与 SingleTask 启动模式一起出现。它会完成 SingleTask 的作用。但事实上 SingleTask 启动模式默认具有此标记位的作用

  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
    其对应在AndroidManifest中的属性为android:excludeFromRecents="true"

    从该Flag的字面意思是将Activity从Recents中排除。那么这个Recents指的是什么意思呢?根据官网的解释是一个刚刚已经加载过的Activity的列表,粗略的也可以理解为Android 手机上多任务管理键被按下去后的效果。

    假设现在App中存在两个Activity A和B,而我们只在AndroidManifest中添加如下代码:

    <activity
        android:name=".Activity_A"
        android:excludeFromRecents="true"/>
    <activity
        android:name=".Activity_B"/>
    

    编译运行之后测试发现即使我们从B中进入主界面再查看多任务管理器列表仍然无法看到。那么为什么会出现这种情况呢?

    通过查阅Android 源码发现,一个Application 中所有的Activity默认会使用同一个taskAffinity属性值,也可以理解为拥有相同的taskAffinity属性值的Activity会处在同一个任务栈中。所以在这种情况下,我们提到的A和B都是处在相同的任务栈中的。而当A中设置了android:excludeFromRecents=”true”之后,系统会将A所处的任务栈从多任务管理器中移除,因此即便我们设置B为加载的入口不进入A依然无法从多任务管理器中出现。

    那么我们如何在同一个App中设置多个任务栈呢?

    答案是通过借助TaskAffinity这个参数,一般情况下所有的Activity都会默认使用相同的taskAffinity参数。我们可以通过在AndroidManifest中规定Activity的taskAffinity属性,并配合singleTask的启动模式来达到我们想要的多任务栈效果。任务栈名称和taskAffinity属性值相同。

    <activity
        android:name=".Activity_A"/>
    <activity
        android:name=".Activity_B"
        android:launchMode="singleTask"
        android:taskAffinity="com.example.Activity_B"/>
    

    在此我们让A处于默认的任务栈中不做修改,让B处于名称为"com.example.Activity_B"的任务栈中,并规定B的启动模式为singleTask。

    当我们启动App,并依次打开Activity A和B。这时我们打开多任务管理器就会看到同一个App的两个任务。

    当我们在Activity A中加入android:excludeFromRecents="true"时,就只会看到多任务管理器中只存在B并不会看到A。

2.7 onNewInstent()方法什么时候执行

这个是启动模式中的了,当此 Activity 的实例已经存在,并且此时的启动模式为 SingleTask 和 SingleInstance ,另外当这个实例位于栈顶且启动模式为 SingleTop 时也会触发onNewInstent()


3. 启动模式

3.1 Activity 间通过 Intent 传递数据大小限制

  • Intent 在传递数据时是有大小限制的,这里官方并未详细说明,不过通过实验的方法可以测出数据应该被限制在 1MB 之内(1024KB)

  • 我们采用传递 Bitmap 的方法,发现当图片大小超过 1024(准确地说是 1020 左右)的时候,程序就会出现闪退、停止运行等异常(不同的手机反应不同)

  • 因此可以判断 Intent 的传输容量在 1MB 之内。

3.2 内存不足时系统会杀掉后台的Activity,若需要进行一些临时状态的保存,在哪个方法进行

  • Activity 的 onSaveInstanceState() 和 onRestoreInstanceState() 并不是生命周期方法,它们不同于 onCreate() 、onPause() 等生命周期方法,它们并不一定会被触发。

  • onSaveInstanceState() 方法,当应用遇到意外情况(如:内存不足、用户直接按 Home 键)由系统销毁一个 Activity ,onSaveInstanceState() 会被调用。

  • 但是当用户主动去销毁一个 Activity 时,例如在应用中按返回键,onSaveInstanceState() 就不会被调用。

  • 除非该 activity 不是被用户主动销毁的,通常 onSaveInstanceState() 只适合用于保存一些临时性的状态,而 onPause() 适合用于数据的持久化保存。

3.2 onSaveInstanceState() 被执行的场景

  • 系统不知道你按下 HOME 后要运行多少其他的程序,自然也不知道 activity A 是否会被销毁

  • 因此系统都会调用 onSaveInstanceState() ,让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则:

1. 当用户按下 HOME 键时
2. 长按 HOME 键,选择运行其他的程序时
3. 锁屏时
4. 从 activity A 中启动一个新的 activity 时
5. 屏幕方向切换时

3.2 scheme 跳转协议

Android中的scheme是一种页面内跳转协议,是一种非常好的实现机制,通过定义自己的scheme协议,可以非常方便跳转App中的各个页面;通过scheme协议,服务器可以定制化告诉App跳转哪个页面,可以通过通知栏消息定制化跳转页面,可以通过H5页面跳转页面等

格式:Uri.parse("qh://test:8080/good?pId=0303&name=zhangsan")

  • qh 代表Scheme协议名称
  • test 代表Scheme作用的地址簿
  • 8080 代表路径的端口号
  • /good 代表的是指定页面(路径)
  • pId和name 代表专递的两个参数

使用实例

1. 在AndroidManifest.xml中设置Scheme
    <activity android:name=".other.SchemeActivity">
        <!-- 要想在别的App上能成功调起App,必须添加intent过滤器 -->
        <intent-filter>
            <!-- 协议部分 -->
            <data
                android:scheme="qh"
                android:host="test"
                android:path="/good"
                android:port="8080"/>
            <!--下面这几行也必须得设置-->
            <category android:name="android.intent.category.DEFAULT"/>
            <action android:name="android.intent.action.VIEW"/>
            <category android:name="android.intent.category.BROWSABLE"/>
        </intent-filter>
    </activity>
2. 调用方式
// 页面调用
<a href="qh://test:8080/good?pId=0303&name=zhangsan">打开商品详情</a>

// 原生调用
/**
 * (1)在manifest配置文件中配置了scheme参数
 * (2)网络端获取url
 * (3)跳转
 */
String url = "scheme://mtime/goodsDetail?goodsId=10011002";

Intent intent = new Intent(Intent.ACTION_VIEW,
        Uri.parse(url));
startActivity(intent);
3. 获取scheme协议参数
public class SchemeActivity extends Activity {
    private static final String TAG = "SchemeActivity";
    private TextView schemeTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scheme);
        schemeTv = (TextView) findViewById(R.id.scheme_tv);
        Uri data = getIntent().getData();
        Log.i(TAG, "host = " + data.getHost() + " path = " + data.getPath() + " query = " + data.getQuery());
        String param = data.getQueryParameter("goodsId");
        schemeTv.setText("获取的参数为:" + param);
    }
}
4. 判断某个Scheme是否有效
    Intent intent = new Intent(Intent.ACTION_VIEW,  
            Uri.parse("qh://test:8080/good?pId=0303&name=zhangsan"));
    List<ResolveInfo> activitys = getPackageManager().queryIntentActivities(intent, 0);
    boolean isValid = activitys.isEmpty();
    if (isValid){
        startActivity(intent);
    }

4. Context

4.1 Context , Activity , Appliction 的区别

  • 相同:Activity 和 Application 都是 Context 的子类。

    Context 从字面上理解就是上下文的意思, 在实际应用中它也确实是起到了管理 上下文环境中各个参数和变量的总用, 方便我们可以简单的访问到各种资源。

  • 不同:维护的生命周期不同。Context 维护的是当前的 Activity 的生命周期, Application 维护的是整个项目的生命周期。

    使用 context 的时候, 小心内存泄露, 防止内存泄露

4.2 Context是什么

它描述的是一个应用程序环境的信息,即上下文。

该类是一个抽象( abstract class )类,  Android 提供了该抽象类的具体实 现类( ContextIml )。

通过它我们可以获取应用程序的资源和类, 也包括一些应用级别操作, 例如:启动一个 Activity ,发送广播,接受 Intent ,信息,等。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容