Activity啟動(dòng)過(guò)程詳解

Activity組件的主要作用是展示一個(gè)界面并和用戶交互,它扮演的是一種前臺(tái)界面的角色,在顯示調(diào)用的情形下,只需要通過(guò)如下代碼即可完成。

 Intent intent=new Intent(this,TestActivity.class);
 startActivity(intent);

通過(guò)上面代碼即可啟動(dòng)一個(gè)具體的Activity,然后這個(gè)Activity就會(huì)被系統(tǒng)啟動(dòng)并展示在用戶的眼前,但是系統(tǒng)內(nèi)部是如何啟動(dòng)一個(gè)Activity的呢?比如新Activity的對(duì)象是何時(shí)創(chuàng)建的,onCreate方法又是在何時(shí)回調(diào)的等等,本文將針對(duì)這些問(wèn)題對(duì)Activity的整體流程進(jìn)行講解。

我們從Activity的startActivity方法開(kāi)始分析,startActivity的方法有好幾種重載方式,它們最終會(huì)調(diào)用startActivityForResult,它的實(shí)現(xiàn)如下所示。

public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
        if (mParent == null) {
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            ...ignore some code...    
        } else {
            if (options != null) {
                 //當(dāng)現(xiàn)在的Activity有父Activity的時(shí)候會(huì)調(diào)用,但是在startActivityFromChild()內(nèi)部實(shí)際還是調(diào)用的mInstrumentation.execStartActivity()
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
         ...ignore some code...    
    }

上面代碼我們只關(guān)注mParent=null這部分邏輯就行,需注意mMainThread.getApplicationThread()這個(gè)參數(shù),它的類型是ApplicationThread,ApplicationThread是ActivityThread的一個(gè)內(nèi)部類,ApplicationThread和ActivityThread在Activity的啟動(dòng)過(guò)程中發(fā)揮著很重要的作用。接著看Instrumentation的execStartActivity方法,代碼如下。

public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
            ...ignore some code...
      try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess();
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
        }
        return null;
    }

從上面代碼可以看出,啟動(dòng)Activity真正的實(shí)現(xiàn)由ActivityManagerNative.getDefault()的startActivity方法來(lái)完成,
這里的ActivityManagerNative.getDefault返回的就是ActivityManagerService的遠(yuǎn)程接口,即ActivityManagerProxy。

public abstract class ActivityManagerNative extends Binder implements IActivityManager
{

//從類聲明上,我們可以看到ActivityManagerNative是Binder的一個(gè)子類,而且實(shí)現(xiàn)了IActivityManager接口
 static public IActivityManager getDefault() {
        return gDefault.get();
    }

 //通過(guò)單例模式獲取一個(gè)IActivityManager對(duì)象,這個(gè)對(duì)象通過(guò)asInterface(b)獲得
 private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };
}


//最終返回的還是一個(gè)ActivityManagerProxy對(duì)象
static public IActivityManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
    
     //這里面的Binder類型的obj參數(shù)會(huì)作為ActivityManagerProxy的成員變量保存為mRemote成員變量,負(fù)責(zé)進(jìn)行IPC通信
        return new ActivityManagerProxy(obj);
    }


}

再看ActivityManagerProxy.startActivity(),在這里面做的事情就是IPC通信,利用Binder對(duì)象,調(diào)用transact(),把所有需要的參數(shù)封裝成Parcel對(duì)象,向AMS發(fā)送數(shù)據(jù)進(jìn)行通信。

public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(callingPackage);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        if (profilerInfo != null) {
            data.writeInt(1);
            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        } else {
            data.writeInt(0);
        }
        if (options != null) {
            data.writeInt(1);
            options.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }

ActivityManagerProxy只是通過(guò)這種方式對(duì)要傳輸給服務(wù)器的數(shù)據(jù)進(jìn)行打包,真正實(shí)現(xiàn)的是ActivityManagerService。

但是這個(gè)地方并不是直接由客戶端傳遞給服務(wù)器,而是通過(guò)Binder驅(qū)動(dòng)進(jìn)行中轉(zhuǎn)。Binder驅(qū)動(dòng)原理暫時(shí)忽略,我們把他當(dāng)做一個(gè)中轉(zhuǎn)站就OK,客戶端調(diào)用ActivityManagerProxy接口里面的方法,把數(shù)據(jù)傳送給Binder驅(qū)動(dòng),然后Binder驅(qū)動(dòng)就會(huì)把這些東西轉(zhuǎn)發(fā)給服務(wù)器的ActivityManagerServices,由ActivityManagerServices去真正的實(shí)施具體的操作。

客戶端:ActivityManagerProxy =====>Binder驅(qū)動(dòng)=====> ActivityManagerService:服務(wù)端

從上面的分析看,,ActivityManagerNative.getDefault()實(shí)際上是AMS,因此Activity的啟動(dòng)過(guò)程轉(zhuǎn)移到了AMS中,接著我們分析AMS的startActivity方法。

@Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, options,
            UserHandle.getCallingUserId());
    }

@Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
            
            ...ignore some code...
            
        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, options, userId, null, null);
    }

可以看出,Activity的啟動(dòng)過(guò)程又轉(zhuǎn)移到了ActivityStackSupervisor的startActivityMayWait方法中了,在startActivityMayWait中又調(diào)用了startActivityLocked方法,然后startActivityLocked方法又調(diào)用了startActivityUncheckedLocked(),此時(shí)要啟動(dòng)的Activity已經(jīng)通過(guò)檢驗(yàn),被認(rèn)為是一個(gè)正當(dāng)?shù)膯?dòng)請(qǐng)求。終于,在這里調(diào)用到了ActivityStack的startActivityLocked(ActivityRecord r, boolean newTask,boolean doResume, boolean keepCurTransition, Bundle options)。
ActivityRecord代表的就是要開(kāi)啟的Activity對(duì)象,里面分裝了很多信息,比如所在的ActivityTask等,如果這是首次打開(kāi)應(yīng)用,那么這個(gè)Activity會(huì)被放到ActivityTask的棧頂。

ActivityStack.startActivityLocked()方法如下:
final void startActivityLocked(ActivityRecord r, boolean newTask,
            boolean doResume, boolean keepCurTransition, Bundle options) {
        
        //ActivityRecord中存儲(chǔ)的TaskRecord信息
        TaskRecord rTask = r.task;
      
         ...ignore some code...
      
        //如果不是在新的ActivityTask(也就是TaskRecord)中的話,就找出要運(yùn)行在的TaskRecord對(duì)象
     TaskRecord task = null;
        if (!newTask) {
            boolean startIt = true;
            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                task = mTaskHistory.get(taskNdx);
                if (task.getTopActivity() == null) {
                    // task中的所有Activity都結(jié)束了
                    continue;
                }
                if (task == r.task) {
                    // 找到了
                    if (!startIt) {
                        task.addActivityToTop(r);
                        r.putInHistory();
                        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                                r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                                (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
                                r.userId, r.info.configChanges, task.voiceSession != null,
                                r.mLaunchTaskBehind);
                        if (VALIDATE_TOKENS) {
                            validateAppTokensLocked();
                        }
                        ActivityOptions.abort(options);
                        return;
                    }
                    break;
                } else if (task.numFullscreen > 0) {
                    startIt = false;
                }
            }
        }

      ...ignore some code...

        // Place a new activity at top of stack, so it is next to interact
        // with the user.
        task = r.task;
        task.addActivityToTop(r);
        task.setFrontOfTask();

        ...ignore some code...

         if (doResume) {
            mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
        }
    }

從ActivityStackSupervisor到ActivityStack,又調(diào)回ActivityStackSupervisor, 看下StackSupervisor.resumeTopActivitiesLocked(this, r, options)

boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
            Bundle targetOptions) {
        if (targetStack == null) {
            targetStack = getFocusedStack();
        }
        // Do targetStack first.
        boolean result = false;
        if (isFrontStack(targetStack)) {
            result = targetStack.resumeTopActivityLocked(target, targetOptions);
        }
        
          ...ignore some code...
        
        return result;
    }

又調(diào)回ActivityStack的resumeTopActivityLocked()方法

final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
        if (inResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }

        boolean result = false;
        try {
            // Protect against recursion.
            inResumeTopActivity = true;
            result = resumeTopActivityInnerLocked(prev, options);
        } finally {
            inResumeTopActivity = false;
        }
        return result;
    }

然后調(diào)用ActivityStack的resumeTopActivityInnerLocked(prev, options)方法,resumeTopActivityInnerLocked方法又調(diào)用了ActivityStackSupervisor的startSpecificActivityLocked方法,源碼如下:

startSpecificActivityLocked(ActivityRecord r,
    boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

       r.task.stack.setLaunchTime(r);

        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
                    // Don't add this if it is a platform component that is marked
                    // to run in multiple processes, because this is actually
                    // part of the framework so doesn't make sense to track as a
                    // separate apk in the process.
                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                           mService.mProcessStats);
                }
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }

            // If a dead object exception was thrown -- fall through to
            // restart the application.
        }
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }

從上面代碼可以看出startSpecificActivityLocked 方法調(diào)用了realStartActivityLocked,為了更清晰地說(shuō)明Activity的啟動(dòng)過(guò)程在ActivityStackSupervisor和ActivityStack之間傳遞順序,下面給出一張圖。

在ActivityStackSupervisor的realStartActivityLocked方法中有如下一段代碼:
  app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                  System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                   r.compat, r.launchedFromPackage, r.task.voiceInteractor, app.repProcState,
                  r.icicle, r.persistentState, results, newIntents, !andResume,
                  mService.isNextTransitionForward(), profilerInfo);
ActivityStackSupervisor和ActivityStack之間傳遞順序.png

app.thread. scheduleLaunchActivity,實(shí)際是調(diào)用ApplicationThreadProxy.scheduleLaunchActivity()方法,ApplicationThreadProxy是ApplicationThreadNative的內(nèi)部類

客戶端:ApplicationThread <=====Binder驅(qū)動(dòng)<===== ApplicationThreadProxy:服務(wù)端

這里和上面的邏輯一樣。ApplicationThreadProxy把數(shù)據(jù)封裝好,利用Binder對(duì)象,調(diào)用transact(),把所有需要的參數(shù)封裝成Parcel對(duì)象,向發(fā)送ApplicationThread數(shù)據(jù),繞了一大圈,Activity的啟動(dòng)過(guò)程最終回到了ApplicationThread,ApplicationThread通過(guò)scheduleLaunchActivity啟動(dòng)Activity,代碼如下所示

 public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
                String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
                PersistableBundle persistentState, List<ResultInfo> pendingResults,
                List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
                 ProfilerInfo profilerInfo) {
 
            updateProcessState(procState, false);

             ActivityClientRecord r = new ActivityClientRecord();
 
            r.token = token;
            r.ident = ident;
             r.intent = intent;
            r.referrer = referrer;
            r.voiceInteractor = voiceInteractor;
             r.activityInfo = info;
             r.compatInfo = compatInfo;
             r.state = state;
            r.persistentState = persistentState;

            r.pendingResults = pendingResults;
            r.pendingIntents = pendingNewIntents;
 
             r.startsNotResumed = notResumed;
            r.isForward = isForward;

            r.profilerInfo = profilerInfo;

             updatePendingConfiguration(curConfig);

             sendMessage(H.LAUNCH_ACTIVITY, r);
        }

在ApplicationThread中,scheduleLaunchActivity實(shí)現(xiàn)很簡(jiǎn)單,就是發(fā)送一個(gè)啟動(dòng)的消息(H.LAUNCH_ACTIVITY)交給Handler處理,這個(gè)Handler就叫H,接著看一下Handler對(duì)消息的處理

private class H extends Handler {
        public static final int LAUNCH_ACTIVITY         = 100;
        public static final int PAUSE_ACTIVITY          = 101;

            //ignore some code

        public vhandleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
           switch (msg.what) {
               case LAUNCH_ACTIVITY: {
                  Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                   final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                   r.packageInfo = getPackageInfoNoCheck(
                           r.activityInfo.applicationInfo, r.compatInfo);
                   handleLaunchActivity(r, null);
                  Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
               } break;
                case RELAUNCH_ACTIVITY: {
                //ignore some code
                }

從 case LAUNCH_ACTIVITY這可以知道,Activity的啟動(dòng)過(guò)程由ActivityThread的handleLaunchActivity實(shí)現(xiàn),源碼如下:

  private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
            //ignore some code
        Activity a = performLaunchActivity(r, customIntent);

            ...

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
           Bundle oldState = r.state;
           handleResumeActivity(r.token, false, r.isForward,
                  !r.activity.mFinished && !r.startsNotResumed);
            ...

從上面源碼看出,performLaunchActivity方法最終完成了Activity對(duì)象的創(chuàng)建和啟動(dòng)過(guò)程,并且ActivityThread通過(guò)handleResumeActivity方法來(lái)調(diào)用被啟動(dòng)Activity的onResume方法,performLaunchActivity這個(gè)方法主要完成了如下幾件事

1.從ActivityClientRecord中獲取待啟動(dòng)的Activity的組件信息
 ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
           r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                   Context.CONTEXT_INCLUDE_CODE);
       }

        ComponentName component = r.intent.getComponent();
       if (component == null) {
            component = r.intent.resolveActivity(
               mInitialApplication.getPackageManager());
           r.intent.setComponent(component);
       }

       if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                   r.activityInfo.targetActivity);
       }
2.通過(guò)Instrumentation的newActivity方法使用類加載器創(chuàng)建Activity對(duì)象
 Activity activity = null;
       try {
           java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
           activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
           StrictMode.incrementExpectedActivityCount(activity.getClass());
           r.intent.setExtrasClassLoader(cl);
           r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
       } catch (Exception e) {
           if (!mInstrumentation.onException(activity, e)) {
               throw new RuntimeException(
                    "Unable to instantiate activity " + component
                   + ": " + e.toString(), e);
            }
       }

Instrumentation的newActivity方法,實(shí)現(xiàn)比較簡(jiǎn)單,就是通過(guò)類加載器來(lái)創(chuàng)建Activity對(duì)象:

 public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
         throws InstantiationException, IllegalAccessException,
           ClassNotFoundException {
        return (Activity)cl.loadClass(className).newInstance();
    }
 
3.通過(guò)LoadApk的makeApplication方法創(chuàng)建Application對(duì)象
public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
         if (mApplication != null) {
            return mApplication;
        }

        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")) {
                 initializeJavaContextClassLoader();
            }
             ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
             appContext.setOuterContext(app);
                ...ignore some code...
if (instrumentation != null) {
            try {
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
               if (!instrumentation.onException(app, e)) {
               ...ignore some code...

從makeApplication的實(shí)現(xiàn)可以看出,如果Application創(chuàng)建過(guò)了,就不會(huì)再創(chuàng)建,這也意味著一個(gè)應(yīng)用只有一個(gè)Application對(duì)象,Application對(duì)象也是通過(guò)Instrumentation(newApplication)完成的,和newActivity一樣,都是通過(guò)類加載器實(shí)現(xiàn)。Application創(chuàng)建后,系統(tǒng)會(huì)通過(guò)Instrumentation的callApplicationOnCreate來(lái)調(diào)用Application的onCreate方法。

4.創(chuàng)建Context對(duì)象并通過(guò)Activity的attach方法完成一些重要數(shù)據(jù)的初始化
 Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
               if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                       + r.activityInfo.name + " with config " + config);
               activity.attach(appContext, this, getInstrumentation(), r.token,
                       r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor);

Context是通過(guò)Activity的attach方法和Activity關(guān)聯(lián)的,除此之后,在attach中Activity還會(huì)完成Window的創(chuàng)建并建立關(guān)聯(lián),這樣當(dāng)Window接到外部輸入事件后就可以將事件傳遞給Activity。

5.調(diào)用Activity的onCreate方法

mInstrumentation.callActivityOnCreate(activity, r.state),由于Activity的onCreate已經(jīng)被調(diào)用,這也意味著Activity已經(jīng)完成了整個(gè)啟動(dòng)過(guò)程。

參考文章

【凱子哥帶你學(xué)Framework】Activity啟動(dòng)過(guò)程全解析

參考書(shū)籍:Android開(kāi)發(fā)藝術(shù)探索

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,250評(píng)論 6 530
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 97,923評(píng)論 3 413
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事?!?“怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,041評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,475評(píng)論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,253評(píng)論 6 405
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,801評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,882評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,023評(píng)論 0 285
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,530評(píng)論 1 331
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,494評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,639評(píng)論 1 366
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,177評(píng)論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,890評(píng)論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,289評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,552評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,242評(píng)論 3 389
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,626評(píng)論 2 370

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