Android應(yīng)用開發(fā)中帽哑,一個App可以創(chuàng)建多少個 Application 對象

問題背景

最近跟群友討論一個技術(shù)問題:

image.png

一個應(yīng)用開啟了多進(jìn)程溯祸,最終到底會創(chuàng)建幾個application對象羽嫡,執(zhí)行幾次onCreate()方法本姥?

有的群友根據(jù)自己的想法給出了猜想

image.png

甚至有的群友直接咨詢起了ChatGPT

image.png

但至始至終都沒有一個最終的結(jié)論。于是乎杭棵,為了弄清這個問題婚惫,我決定先寫個demo測試得出結(jié)論,然后從源碼著手分析原因

Demo驗(yàn)證

首先創(chuàng)建了一個app項(xiàng)目魂爪,開啟多進(jìn)程

<?xml version="1.0" encoding="utf-8"?>
<manifest    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools">
    <application        android:name=".DemoApplication"        android:allowBackup="true"        android:dataExtractionRules="@xml/data_extraction_rules"        android:fullBackupContent="@xml/backup_rules"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:roundIcon="@mipmap/ic_launcher_round"        android:supportsRtl="true"        android:theme="@style/Theme.Demo0307"        tools:targetApi="31">
        <!--android:process 開啟多進(jìn)程并設(shè)置進(jìn)程名-->
        <activity            android:name=".MainActivity"            android:exported="true"            android:process=":remote">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

然后在DemoApplication的onCreate()方法打印application對象的地址先舷,當(dāng)前進(jìn)程名稱

public class DemoApplication extends Application {
    private static final String TAG = "jasonwan";
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "Demo application onCreate: " + this + ", processName=" + getProcessName(this));
    }
    private String getProcessName(Application app) {
        int myPid = Process.myPid();
        ActivityManager am = (ActivityManager) app.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);        List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = am.getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo runningAppProcess : runningAppProcesses) {
            if (runningAppProcess.pid == myPid) {
                return runningAppProcess.processName;
            }
        }
        return "null";
            }
        }

運(yùn)行,得到的日志如下

2023-03-07 11:15:27.785 19563-19563/com.jason.demo0307 D/jasonwan: Demo application onCreate: com.jason.demo0307.DemoApplication@fb06c2d, processName=com.jason.demo0307:remote

查看當(dāng)前應(yīng)用所有進(jìn)程

image.png

說明此時app只有一個進(jìn)程滓侍,且只有一個application對象蒋川,對象地址為@fb06c2d

現(xiàn)在我們將進(jìn)程增加到多個,看看情況如何

<?xml version="1.0" encoding="utf-8"?>
<manifest    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools">
    <application        android:name=".DemoApplication"        android:allowBackup="true"        android:dataExtractionRules="@xml/data_extraction_rules"        android:fullBackupContent="@xml/backup_rules"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:roundIcon="@mipmap/ic_launcher_round"        android:supportsRtl="true"        android:theme="@style/Theme.Demo0307"        tools:targetApi="31">
        <!--android:process 開啟多進(jìn)程并設(shè)置進(jìn)程名-->
        <activity            android:name=".MainActivity"            android:exported="true"            android:process=":remote">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity            android:name=".TwoActivity"            android:process=":remote2" />
        <activity            android:name=".ThreeActivity"            android:process=":remote3" />
        <activity            android:name=".FourActivity"            android:process=":remote4" />
        <activity            android:name=".FiveActivity"            android:process=":remote5" />
    </application>
</manifest>

邏輯是點(diǎn)擊MainActivity啟動TwoActivity粗井,點(diǎn)擊TwoActivity啟動ThreeActivity尔破,以此類推。最后我們運(yùn)行浇衬,啟動所有Activity得到的日志如下

2023-03-07 11:25:35.433 19955-19955/com.jason.demo0307 D/jasonwan: Demo application onCreate: com.jason.demo0307.DemoApplication@fb06c2d, processName=com.jason.demo0307:remote
2023-03-07 11:25:43.795 20001-20001/com.jason.demo0307 D/jasonwan: Demo application onCreate: com.jason.demo0307.DemoApplication@fb06c2d, processName=com.jason.demo0307:remote2
2023-03-07 11:25:45.136 20046-20046/com.jason.demo0307 D/jasonwan: Demo application onCreate: com.jason.demo0307.DemoApplication@fb06c2d, processName=com.jason.demo0307:remote3
2023-03-07 11:25:45.993 20107-20107/com.jason.demo0307 D/jasonwan: Demo application onCreate: com.jason.demo0307.DemoApplication@fb06c2d, processName=com.jason.demo0307:remote4
2023-03-07 11:25:46.541 20148-20148/com.jason.demo0307 D/jasonwan: Demo application onCreate: com.jason.demo0307.DemoApplication@fb06c2d, processName=com.jason.demo0307:remote5

查看當(dāng)前應(yīng)用所有進(jìn)程

image.png

此時app有5個進(jìn)程懒构,但application對象地址均為@fb06c2d,地址相同意味著它們是同一個對象耘擂。

那是不是就可以得出結(jié)論胆剧,無論啟動多少個進(jìn)程都只會創(chuàng)建一個application對象呢?并不能妄下此定論醉冤,我們將MainActivity的process屬性去掉再運(yùn)行秩霍,得到的日志如下

2023-03-07 11:32:10.156 20318-20318/com.jason.demo0307 D/jasonwan: Demo application onCreate: com.jason.demo0307.DemoApplication@5d49e29, processName=com.jason.demo0307
2023-03-07 11:32:15.143 20375-20375/com.jason.demo0307 D/jasonwan: Demo application onCreate: com.jason.demo0307.DemoApplication@fb06c2d, processName=com.jason.demo0307:remote
22023-03-07 11:32:16.477 20417-20417/com.jason.demo0307 D/jasonwan: Demo application onCreate: com.jason.demo0307.DemoApplication@fb06c2d, processName=com.jason.demo0307:remote
32023-03-07 11:32:17.582 20463-20463/com.jason.demo0307 D/jasonwan: Demo application onCreate: com.jason.demo0307.DemoApplication@fb06c2d, processName=com.jason.demo0307:remote4
2023-03-07 11:32:18.882 20506-20506/com.jason.demo0307 D/jasonwan: Demo application onCreate: com.jason.demo0307.DemoApplication@fb06c2d, processName=com.jason.demo0307:remote5

查看當(dāng)前應(yīng)用所有進(jìn)程

image.png

此時app有5個進(jìn)程,但有2個application對象蚁阳,對象地址為@5d49e29@fb06c2d铃绒,且子進(jìn)程的application對象都相同。

上述所有進(jìn)程的父進(jìn)程ID為678螺捐,而此進(jìn)程正是zygote進(jìn)程

image.png

根據(jù)上面的測試結(jié)果我們目前能得出的結(jié)論:

  • 結(jié)論1:單進(jìn)程只創(chuàng)建一個Application對象颠悬,執(zhí)行一次onCreate()方法矮燎;
  • 結(jié)論2:多進(jìn)程至少創(chuàng)建2個Application對象,執(zhí)行多次onCreate()方法赔癌,幾個進(jìn)程就執(zhí)行幾次诞外;

結(jié)論2為什么說至少創(chuàng)建2個,因?yàn)槲以诩闪薐Push的商業(yè)項(xiàng)目中測試發(fā)現(xiàn)灾票,JPush創(chuàng)建的進(jìn)程跟我自己創(chuàng)建的進(jìn)程峡谊,Application地址是不同的。

image.png

這里三個進(jìn)程刊苍,分別創(chuàng)建了三個Application對象既们,對象地址分別是@f31ba9d@2c586f3班缰,@fb06c2d

源碼分析

Application 的創(chuàng)建位于 frameworks/base/core/java/android/app/ActivityThread.java 的handleBindApplication()方法中

    @UnsupportedAppUsage    private void handleBindApplication(AppBindData data) {
            long st_bindApp = SystemClock.uptimeMillis();
            //省略部分代碼
            // Note when this process has started.
            //設(shè)置進(jìn)程啟動時間
            Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
            //省略部分代碼
            // send up app name; do this *before* waiting for debugger
            //設(shè)置進(jìn)程名稱
            Process.setArgV0(data.processName);
            //省略部分代碼
            // Allow disk access during application and provider setup. This could
            // block processing ordered
     broadcasts, but later processing would
            // probably end up doing the same disk access.
                    Application app;
            final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
            final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();
            try {
                // If the app is being launched for full backup or restore, bring it up in
                // a restricted environment with the base application class. 
               //此處開始創(chuàng)建application對象贤壁,注意參數(shù)2為null 
               app = data.info.makeApplication(data.restrictedBackupMode, null);
                //省略部分代碼
                try {
                    if ("com.jason.demo0307".equals(app.getPackageName())){
                        Log.d("jasonwan", "execute app onCreate(), app=:"+app+", processName="+getProcessName(app)+", pid="+Process.myPid());
                    }
                    //執(zhí)行application的onCreate方法()
                    mInstrumentation.callApplicationOnCreate(app);
                } catch (Exception e) {
                    if (!mInstrumentation.onException(app, e)) {
                        throw new RuntimeException(
                          "Unable to create application " + app.getClass().getName()
                          + ": " + e.toString(), e);
                    }
                }
            } finally {
                // If the app targets < O-MR1, or doesn't change the thread policy
                // during startup, clobber the policy to maintain behavior of b/36951662
                if (data.appInfo.targetSdkVersion < Build.VERSION_CODES.O_MR1
                        ||
     StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) {
                    StrictMode.setThreadPolicy(savedPolicy);
                }        }
            //省略部分代碼
        }

實(shí)際創(chuàng)建過程在 frameworks/base/core/java/android/app/LoadedApk.java 中的makeApplication()方法中,LoadedApk 顧名思義就是加載好的Apk文件埠忘,里面包含Apk所有信息,像包名馒索、Application對象莹妒,app所在的目錄等,這里直接看application的創(chuàng)建過程

    @UnsupportedAppUsage
        public Application makeApplication(boolean forceDefaultAppClass,            Instrumentation instrumentation) {
            if ("com.jason.demo0307".equals(mApplicationInfo.packageName)) {
                Log.d("jasonwan", "makeApplication: mApplication="+mApplication+", pid="+Process.myPid());
            }
            //如果已經(jīng)創(chuàng)建過了就不再創(chuàng)建
            if (mApplication != null) {
                return mApplication;
            }
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
            Application app = null;
            String appClass = mApplicationInfo.className;
            if (forceDefaultAppClass || (appClass == null)) {
                appClass = "android.app.Application";
            }
            try {
                java.lang.ClassLoader cl = getClassLoader();
                if (!mPackageName.equals("android")) {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,                        "initializeJavaContextClassLoader");
                    initializeJavaContextClassLoader();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                }
                ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
                //反射創(chuàng)建application對象
                app = mActivityThread.mInstrumentation.newApplication(                    cl, appClass, appContext);
                if("com.jason.demo0307.DemoApplication".equals(appClass)){
                    Log.d("jasonwan", "create application, app="+app+", processName="+mActivityThread.getProcessName()+", pid="+Process.myPid());
                }
                            appContext.setOuterContext(app);
            } catch (Exception e) {
                Log.d("jasonwan", "fail to create application, "+e.getMessage());
                if (!mActivityThread.mInstrumentation.onException(app, e)) {
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    throw new RuntimeException(
                                        "Unable to instantiate application " + appClass
                        + ": " + e.toString(), e);
                }
            }
            mActivityThread.mAllApplications.add(app);
            mApplication = app;
            if (instrumentation != null) {
                try {
                    //第一次啟動創(chuàng)建時绰上,instrumentation為null旨怠,不會執(zhí)行onCreate()方法                instrumentation.callApplicationOnCreate(app);
                } catch (Exception e) {
                    if
     (!instrumentation.onException(app, e)) {
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                        throw new RuntimeException(
                                                "Unable to create application " + app.getClass().getName()
                                                                        + ": " + e.toString(), e);
                    }
                }
            }
            // 省略部分代碼
            return app;
        }

為了看清application到底被創(chuàng)建了幾次,我在關(guān)鍵地方埋下了log蜈块,TAG為jasonwan的log是我自己加的鉴腻,編譯驗(yàn)證,得到如下log

啟動app百揭,進(jìn)入MainActivity
03-08 17:20:29.965  4069  4069 D jasonwan: makeApplication: mApplication=null, pid=4069
//創(chuàng)建application對象爽哎,地址為@c2f8311,當(dāng)前進(jìn)程id為4069
03-08 17:20:29.967  4069  4069 D jasonwan: create application, app=com.jason.demo0307.DemoApplication@c2f8311, processName=com.jason.demo0307, pid=4069
03-08 17:20:29.988  4069  4069 D jasonwan: execute app onCreate(), app=:com.jason.demo0307.DemoApplication@c2f8311, processName=com.jason.demo0307, pid=4069
03-08 17:20:29.989  4069  4069 D jasonwan: DemoApplication=com.jason.demo0307.DemoApplication@c2f8311, processName=com.jason.demo0307, pid=4069
03-08 17:20:36.614  4069  4069 D jasonwan: makeApplication: mApplication=com.jason.demo0307.DemoApplication@c2f8311, pid=4069
點(diǎn)擊MainActivity器一,跳轉(zhuǎn)到TwoActivity
03-08 17:20:39.686  4116  4116 D jasonwan: makeApplication: mApplication=null, pid=4116
//創(chuàng)建application對象课锌,地址為@c2f8311,當(dāng)前進(jìn)程id為4116
03-08 17:20:39.687  4116  4116 D jasonwan: create application, app=com.jason.demo0307.DemoApplication@c2f8311, processName=com.jason.demo0307:remote2, pid=4116
03-08 17:20:39.688  4116  4116 D jasonwan: execute app onCreate(), app=:com.jason.demo0307.DemoApplication@c2f8311, processName=com.jason.demo0307:remote2, pid=4116
03-08 17:20:39.688  4116  4116 D jasonwan: DemoApplication=com.jason.demo0307.DemoApplication@c2f8311, processName=com.jason.demo0307:remote2, pid=4116
03-08 17:20:39.733  4116  4116 D jasonwan: makeApplication: mApplication=com.jason.demo0307.DemoApplication@c2f8311, pid=4116
點(diǎn)擊TwoActivity祈秕,跳轉(zhuǎn)到ThreeActivity
03-08 17:20:41.473  4147  4147 D jasonwan: makeApplication: mApplication=null, pid=4147
//創(chuàng)建application對象渺贤,地址為@c2f8311,當(dāng)前進(jìn)程id為4147
03-08 17:20:41.475  4147  4147 D jasonwan: create application, app=com.jason.demo0307.DemoApplication@c2f8311, processName=com.jason.demo0307:remote3, pid=4147
03-08 17:20:41.475  4147  4147 D jasonwan: execute app onCreate(), app=:com.jason.demo0307.DemoApplication@c2f8311, processName=com.jason.demo0307:remote3, pid=4147
03-08 17:20:41.476  4147  4147 D jasonwan: DemoApplication=com.jason.demo0307.DemoApplication@c2f8311, processName=com.jason.demo0307:remote3, pid=4147
03-08 17:20:41.519  4147  4147 D jasonwan: makeApplication: mApplication=com.jason.demo0307.DemoApplication@c2f8311, pid=4147
點(diǎn)擊ThreeActivity请毛,跳轉(zhuǎn)到FourActivity
03-08 17:20:42.966  4174  4174 D jasonwan: makeApplication: mApplication=null, pid=4174
//創(chuàng)建application對象志鞍,地址為@c2f8311,當(dāng)前進(jìn)程id為4174
03-08 17:20:42.968  4174  4174 D jasonwan: create application, app=com.jason.demo0307.DemoApplication@c2f8311, processName=com.jason.demo0307:remote4, pid=4174
03-08 17:20:42.969  4174  4174 D jasonwan: execute app onCreate(), app=:com.jason.demo0307.DemoApplication@c2f8311, processName=com.jason.demo0307:remote4, pid=4174
03-08 17:20:42.969  4174  4174 D jasonwan: DemoApplication=com.jason.demo0307.DemoApplication@c2f8311, processName=com.jason.demo0307:remote4, pid=4174
03-08 17:20:43.015  4174  4174 D jasonwan: makeApplication: mApplication=com.jason.demo0307.DemoApplication@c2f8311, pid=4174
點(diǎn)擊FourActivity方仿,跳轉(zhuǎn)到FiveActivity
03-08 17:20:44.426  4202  4202 D jasonwan: makeApplication: mApplication=null, pid=4202
//創(chuàng)建application對象固棚,地址為@c2f8311统翩,當(dāng)前進(jìn)程id為4202
03-08 17:20:44.428  4202  4202 D jasonwan: create application, app=com.jason.demo0307.DemoApplication@c2f8311, processName=com.jason.demo0307:remote5, pid=4202
03-08 17:20:44.429  4202  4202 D jasonwan: execute app onCreate(), app=:com.jason.demo0307.DemoApplication@c2f8311, processName=com.jason.demo0307:remote5, pid=4202
03-08 17:20:44.430  4202  4202 D jasonwan: DemoApplication=com.jason.demo0307.DemoApplication@c2f8311, processName=com.jason.demo0307:remote5, pid=4202
03-08 17:20:44.473  4202  4202 D jasonwan: makeApplication: mApplication=com.jason.demo0307.DemoApplication@c2f8311, pid=4202

結(jié)果很震驚,我們在5個進(jìn)程中創(chuàng)建的application對象玻孟,地址均為@c2f8311唆缴,也就是至始至終創(chuàng)建的都是同一個Application對象,那么上面的結(jié)論2顯然并不成立黍翎,只是測試的偶然性導(dǎo)致的面徽。

可真的是這樣子的嗎,這也太顛覆我的三觀了匣掸,為此我跟群友討論了這個問題:

不同進(jìn)程中的多個對象趟紊,內(nèi)存地址相同,是否代表這些對象都是同一個對象碰酝?

群友的想法是霎匈,java中獲取的都是虛擬內(nèi)存地址,虛擬內(nèi)存地址相同送爸,不代表是同一個對象铛嘱,必須物理內(nèi)存地址相同,才表示是同一塊內(nèi)存空間袭厂,也就意味著是同一個對象墨吓,物理內(nèi)存地址和虛擬內(nèi)存地址存在一個映射關(guān)系,同時給出了java中獲取物理內(nèi)存地址的方法Android獲取對象地址纹磺,主要是利用Unsafe這個類來操作帖烘,這個類有一個作用就是直接訪問系統(tǒng)內(nèi)存資源。因?yàn)檫@種操作是不安全的橄杨,所以被標(biāo)為了私有秘症,但我們可以通過反射去調(diào)用此API, 然后我又去請教了部門搞寄存器的大佬式矫,大佬肯定了群友的想法乡摹,于是我添加代碼,嘗試獲取對象的物理內(nèi)存地址衷佃,看看是否相同

public class DemoApplication extends Application {
    public static final String TAG = "jasonwan";
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "DemoApplication=" + this + ", address=" + addressOf(this) + ", pid=" + Process.myPid());
    }
    //獲取對象的真實(shí)物理地址
    public static long addressOf(Object o) {
        Object[] array = new Object[]{o};
        long objectAddress = -1;
        try {
            Class cls = Class.forName("sun.misc.Unsafe");
            Field field = cls.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            Object unsafe = field.get(null);
            Class unsafeCls = unsafe.getClass();
            Method arrayBaseOffset = unsafeCls.getMethod("arrayBaseOffset", Object.class.getClass());
            int baseOffset = (int) arrayBaseOffset.invoke(unsafe, Object[].class);
            Method size = unsafeCls.getMethod("addressSize");
            int addressSize = (int) size.invoke(unsafe);
            switch (addressSize) {
                            case 4:
                    Method getInt = unsafeCls.getMethod("getInt", Object.class, long.class);
                    objectAddress = (int) getInt.invoke(unsafe, array, baseOffset);
                    break;
                case 8:
                    Method getLong = unsafeCls.getMethod("getLong", Object.class, long.class);
                    objectAddress = (long) getLong.invoke(unsafe, array, baseOffset);
                    break;
                default:
                    throw new Error("unsupported address size: " + addressSize);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return objectAddress;
    }
}

運(yùn)行后得到如下日志

2023-03-10 11:01:54.043 6535-6535/com.jason.demo0307 D/jasonwan: 
DemoApplication=com.jason.demo0307.DemoApplication@930d275, address=8050489105119022792, pid=6535
2023-03-10 11:02:22.610 6579-6579/com.jason.demo0307 D/jasonwan: 
DemoApplication=com.jason.demo0307.DemoApplication@331b3b9, address=8050489105119027136, pid=6579
2023-03-10 11:02:36.369 6617-6617/com.jason.demo0307 D/jasonwan: 
DemoApplication=com.jason.demo0307.DemoApplication@331b3b9, address=8050489105119029912, pid=6617
2023-03-10 11:02:39.244 6654-6654/com.jason.demo0307 D/jasonwan: 
DemoApplication=com.jason.demo0307.DemoApplication@331b3b9, address=8050489105119032760, pid=6654
2023-03-10 11:02:40.841 6692-6692/com.jason.demo0307 D/jasonwan: 
DemoApplication=com.jason.demo0307.DemoApplication@331b3b9, address=8050489105119036016, pid=6692
2023-03-10 11:02:52.429 6729-6729/com.jason.demo0307 D/jasonwan: 
DemoApplication=com.jason.demo0307.DemoApplication@331b3b9, address=8050489105119038720, pid=6729

可以看到趟卸,雖然Application的虛擬內(nèi)存地址相同,都是331b3b9氏义,但它們的真實(shí)物理地址卻不同锄列。

至此,我們可以得出最終結(jié)論:

  • 單進(jìn)程惯悠,創(chuàng)建1個application對象邻邮,執(zhí)行一次onCreate()方法
  • 多進(jìn)程(N),創(chuàng)建N個application對象克婶,執(zhí)行N次onCreate()方法
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末筒严,一起剝皮案震驚了整個濱河市丹泉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鸭蛙,老刑警劉巖摹恨,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異娶视,居然都是意外死亡晒哄,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門肪获,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寝凌,“玉大人,你說我怎么就攤上這事孝赫〗夏荆” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵青柄,是天一觀的道長伐债。 經(jīng)常有香客問我,道長致开,這世上最難降的妖魔是什么昧互? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任孟害,我火速辦了婚禮,結(jié)果婚禮上妆距,老公的妹妹穿的比我還像新娘校坑。我一直安慰自己拣技,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布耍目。 她就那樣靜靜地躺著膏斤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪邪驮。 梳的紋絲不亂的頭發(fā)上莫辨,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機(jī)與錄音毅访,去河邊找鬼沮榜。 笑死,一個胖子當(dāng)著我的面吹牛喻粹,可吹牛的內(nèi)容都是我干的蟆融。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼守呜,長吁一口氣:“原來是場噩夢啊……” “哼型酥!你這毒婦竟也來了山憨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤弥喉,失蹤者是張志新(化名)和其女友劉穎郁竟,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體由境,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡棚亩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了藻肄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蔑舞。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖嘹屯,靈堂內(nèi)的尸體忽然破棺而出攻询,到底是詐尸還是另有隱情,我是刑警寧澤州弟,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布钧栖,位于F島的核電站,受9級特大地震影響婆翔,放射性物質(zhì)發(fā)生泄漏拯杠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一啃奴、第九天 我趴在偏房一處隱蔽的房頂上張望潭陪。 院中可真熱鬧,春花似錦最蕾、人聲如沸依溯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽黎炉。三九已至,卻和暖如春醋拧,著一層夾襖步出監(jiān)牢的瞬間慷嗜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工丹壕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留庆械,地道東北人。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓雀费,卻偏偏與公主長得像干奢,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子盏袄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355

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