Activity的啟動過程分析

Activity的啟動過程

首先先列出Activity啟動的過程中調(diào)用的一些方法,因為activity啟動涉及到各種方法調(diào)用幔妨,而且調(diào)用的路線也各不一樣,這里只會對activity啟動的一條線進行分析谍椅,有興趣的同學(xué)可以讀android的源碼進行分析

  1. Activity
    • startActivity
    • startActivityForResult
  2. Instrumentation
    • execStartActivity
  3. ActivityManagerProxy
    • startActivity
  4. ActivityManagerService
    • startActivity
    • startActivityAsUser
  5. ActivityStarter
    • startActivityMayWait
    • startActivityLocked
    • startActivityUnchecked
    • postStartActivityUncheckedProcessing
  6. ActivityStack
    • startActivityLocked
  7. ActivityStackSupervisor
    • resumeFocusedStackTopActivityLocked
  8. ActivityStack
    • resumeTopActivityUncheckedLocked
    • resumeTopActivityInnerLocked
  9. ActivityThread
    • scheduleLaunchActivity
    • H(Handler) - LAUNCH_ACTIVITY

通過源碼發(fā)現(xiàn)误堡,startActivity進入到startActivityForResult的方法,然后進入到Instrumentation的execStartActivity方法雏吭。

在進入Instrumentation之前锁施,先對Instrumentation做簡短的介紹:

  1. 其包含有2個內(nèi)部類:ActivityMoniter、ActivityResult

    ActivityMoniter:有關(guān)特定的Intent的監(jiān)視杖们。一個ActivityMoniter類的實例通過函數(shù)addMonitor(Instrumentation.ActivityMonitor)添加到當(dāng)前instrumentation中悉抵,一旦添加后,每當(dāng)啟動一個新的Activity摘完,ActivityMoniter就會檢測姥饰,如果匹配,其hit count計數(shù)更新等其他操作孝治。 一個ActivityMonitor也可以用來尋找一個Activity列粪,通過waitForActivity()方法,這個函數(shù)將返直到匹配的活動被創(chuàng)建谈飒。
    ActivityResult:一個活動執(zhí)行的結(jié)果說明岂座,返回到原來的活動。

  2. 創(chuàng)建步绸,暫停和恢復(fù)Activity的時候掺逼,都是通過調(diào)用Instrumentation的callActivityOnCreate,callActivityOnPause和callActivityOnResume等方法來實現(xiàn)對Activity方法生命周期調(diào)用


    public void startActivity(Intent intent) {
        this.startActivity(intent, null);
    }


    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            // 跳出Activity方法瓤介,進入到execStartActivity方法
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                // 通知Activity啟動的結(jié)果吕喘,這里會調(diào)用棧頂?shù)腁ctivity調(diào)用onPause方法
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
            // 這里是低版本的系統(tǒng)啟動Activity的方式,這里不進行分析
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

我們進入到Instrumentation的execStartActivity方法,下面對execStartActivity的參數(shù)進行解析,
從源碼可以看出刑桑,Instrumentation直接進入了ActivityManagerNative的startActivity方法氯质,隨后會調(diào)用checkStartActivityResult,這個方法會檢查返回結(jié)果是否中Activity是否在AndroidManifest.xml中注冊,如果沒有就會拋出異常等祠斧。


    public class Instrumentation {

        ...省略代碼

        public ActivityResult execStartActivity(...省略參數(shù)) {
            ...省略代碼
            // 進入到ActivityManagerProxy
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);

            // 檢查startActivity返回結(jié)果是否成功
            checkStartActivityResult(result, intents[0]);
            ...省略代碼
            return null;
        }

        public static void checkStartActivityResult(...省略參數(shù)) {
            if (res >= ActivityManager.START_SUCCESS) {
                return;
            }
    
            switch (res) {
                ...省略代碼
                // 此處是沒有在AndroidManifest.xml里注冊Activity時報的
                case ActivityManager.START_INTENT_NOT_RESOLVED:
                case ActivityManager.START_CLASS_NOT_FOUND:
                    if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
                        throw new ActivityNotFoundException(
                                "Unable to find explicit activity class "
                                + ((Intent)intent).getComponent().toShortString()
                                + "; have you declared this activity in your AndroidManifest.xml?");
                    throw new ActivityNotFoundException(
                            "No Activity found to handle " + intent);
                ...省略代碼
            }
        }

        ...省略代碼
    }

然后我們進入到ActivityManagerNative,下面對Activity的參數(shù)進行分析

  1. who:Activity的啟動者
  2. contextThread:當(dāng)前Activity的啟動進程
  3. token:記錄啟動Activity的token值闻察,有可能為空
  4. target:啟動者,即啟動新Activity的那個Activity
  5. intent:意圖
  6. requestCode:啟動Activity后,返回給當(dāng)前Activity的值辕漂,通過onActivityResult返回
  7. options:附加參數(shù)

而ActivityMangagerNitive調(diào)用的是ActivityManagerProxy的startActivity方法,最后調(diào)用mRemote方法呢灶,mRemote是Binder類型,由此可見這里startActivity是通過調(diào)用遠程ActivityManagerService的binder調(diào)用的是遠程的onStransct方法,而ActivityManagerService是ActivityMangagerNitive的子類,onStransct的實現(xiàn)是在ActivityMangagerNitive钉嘹,所以我們進入到ActivityMangagerNitive鸯乃,從ActivityMangagerNitive的onTransact方法可以看出調(diào)用的是子類的startActivity方法,我們知道ActivityManagerNative的子類是ActivityManagerService跋涣。

這里涉級到一個技巧缨睡,我們每個Activity都必須到AndroidManifest.xml里面去注冊否則我們就無法啟動這個Activity,我們是否想到有沒有可能不注冊Activity就能啟動這個Activity呢陈辱?答案是肯定的奖年,我們可以在AndroidManifest.xml里面注冊一個代理的Activity,只要在進入ActivityManagerNative方法后,我們把我們的啟動Activity換成一個在AndroidManifest.xml中己經(jīng)注冊好的代理類Activity沛贪,這樣就可以欺騙系統(tǒng)說陋守,我己經(jīng)注冊了這個Activity了,你不需要拋出找不到Activity的異常鹏浅。


    public abstract class ActivityManagerNative extends Binder implements IActivityManager

        // 這是遠程ActivityManagerService的onTransact方法
        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
                throws RemoteException {
            switch (code) {
            // 根據(jù)傳過來的code類型嗅义,我們知道會調(diào)用到進入到下面的case去
            case START_ACTIVITY_TRANSACTION:
            {
                ....省略代碼
                // 調(diào)用startActivity方法,具體的實現(xiàn)在ActivityManagerService
                int result = startActivity(app, callingPackage, intent, resolvedType,
                        resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
                ...省略代碼
                return true;
            }
        }

        class ActivityManagerProxy implements IActivityManager
    
            ...省略代碼
            public int startActivity(...省略參數(shù)) throws RemoteException {
                ...
                // 調(diào)用遠程的transact方法隐砸,帶上START_ACTIVITY_TRANSACTION的code類型
                // 并把所有的參數(shù)都帶到遠程去
                mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
                ...
                return result;
            }
    
            ...省略代碼
        }
    }

下面我們分析ActivityManagerService的startActivity方法之碗,startActivity調(diào)用的是startActivityAsUsery方法,startActivity比startActivityAsUsery多出了UserId,有了這個UserId季希,就可以檢查調(diào)用者的權(quán)限褪那。而startActivityAsUser會跳到ActivityStarter的startActivityMayWait方法


    public final class ActivityManagerService extends ActivityManagerNative
            implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

        ...省略代碼

        @Override
        public final int startActivity(...省略參數(shù)) {
            return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, UserHandle.getCallingUserId());
        }

        ...省略代碼


        @Override
        public final int startActivityAsUser(...省略參數(shù)) {
            ...省略代碼
            // 跳出ActivityManagerSerivce,進入到ActivityStarter的startActivityMayWait方法
            return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                    profilerInfo, null, null, bOptions, false, userId, null, null);
        }

    }

下面我們進入到ActivityStarter類,因為ActivityStarter類涉及的方法太多式塌,這里只是會分析幾個重要的調(diào)用:

  1. 首先博敬,我們進入到ActivityStarter的startActivityMayWait方法 此方法里面mSupervisor.resolveIntent(intent, resolvedType, userId)會進入到PackageManagerService的resolveIntent方法,此方法是開發(fā)者使用隱式調(diào)用時峰尝,會彈出選擇窗讓用戶自己使擇打開的應(yīng)用

  2. 然后偏窝,我們進入到了ActivityStarter的startActivityLocked方法, 此方法大部份是對調(diào)用者的權(quán)限進行驗證武学,看是否調(diào)用者是否有權(quán)限進行操作

  1. 然后進入到ActivityStarter的startActivityUnchecked方法祭往,此方法主要是判斷Activity是以什么方式啟動,還有以什么方式入Activity棧, 例如computeLaunchingTaskFlags(); 判斷Activity啟動的以什么方式啟動

  2. 然后我們進入到ActivityStack的startActivityLocked方法火窒,這方法主要是設(shè)置Activity的準(zhǔn)備工作己經(jīng)完成

  3. 最后由postStartActivityUncheckedProcessing方法發(fā)出通知Activity的啟動工作完成


    class ActivityStarter {
        
        final int startActivityMayWait(...省略參數(shù)) {
                
                ...省略代碼

                ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);

                ...省略代碼

                // 進入到startActivityLocked方法硼补,此方法主要是檢查Activity啟動的權(quán)限
                int res = startActivityLocked(caller, intent, ephemeralIntent,  resolvedType, aInfo, rInfo, voiceSession, voiceInteractor,
                    resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                    inTask);
    
                ...省略代碼

                return res;
            }
        }


        final int startActivityLocked(...省略參數(shù)) {

            ....省略代碼
            
            // 
            if (abort) {
                if (resultRecord != null) {
                    resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
                            RESULT_CANCELED, null);
                }
                // We pretend to the caller that it was really started, but
                // they will just get a cancel result.
                ActivityOptions.abort(options);
                return START_SUCCESS;
            }
    
            try {
                err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true, options, inTask);
            } finally {
                mService.mWindowManager.continueSurfaceLayout();
            }
            postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord,     mTargetStack);
            return err;
        }


        private int startActivityUnchecked(final ActivityRecord r, ActivityRecord   sourceRecord,   sume, ActivityOptions options,  TaskRecord inTask) {

            setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession, voiceInteractor);
    
            // 還是用來初始化啟動標(biāo)志位的
            computeLaunchingTaskFlags();
    
            computeSourceStack();
    
            ...省略代碼
    
            mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);

            ...省略代碼

            return START_SUCCESS;
        }

        void postStartActivityUncheckedProcessing(
            ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord,
            ActivityStack targetStack) {

            ...省略代碼
        
            // We're waiting for an activity launch to finish, but that activity simply
            // brought another activity to front. Let startActivityMayWait() know about
            // this, so it waits for the new activity to become visible instead.
            if (result == START_TASK_TO_FRONT && !mSupervisor.mWaitingActivityLaunched.isEmpty()) {
                mSupervisor.reportTaskToFrontNoLaunch(mStartActivity);
            }

            ...省略代碼

        }

        ...省略代碼
    }



    final class ActivityStack {
        
        ...省略代碼

        final void startActivityLocked(ActivityRecord r, boolean newTask, boolean keepCurTransition,
                ActivityOptions options) {
        
            ...省略代碼

            // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
            // tell WindowManager that r is visible even though it is at the back of the stack.
            mWindowManager.setAppVisibility(r.appToken, true);

            ...

        }
        
        ...

    }

下面我們進入到ActivityStackSupervisor源碼,reportTaskToFrontNoLaunch的作用是如果change為true就通知通知ActivityStarter待啟動Activity對應(yīng)的Task移動到了前臺


    public final class ActivityStackSupervisor implements DisplayListener {

        ...省略代碼

        void reportTaskToFrontNoLaunch(ActivityRecord r) {
            boolean changed = false;
            for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) {
                WaitResult w = mWaitingActivityLaunched.remove(i);
                if (w.who == null) {
                    changed = true;
                    // Set result to START_TASK_TO_FRONT so that startActivityMayWait() knows that
                    // the starting activity ends up moving another activity to front, and it should
                    // wait for this new activity to become visible instead.
                    // Do not modify other fields.
                    w.result = START_TASK_TO_FRONT;
                }
            }
            if (changed) {
                //notifyAll通知ActivityStarter待啟動Activity對應(yīng)的Task移動到了前臺
                mService.notifyAll();
            }
        }

        ...省略代碼

    }

發(fā)送通知后熏矿,就會調(diào)用ActivityStackSupervisor的resumeFocusedStackTopActivityLocked方法已骇,然后調(diào)ActivityStack的resumeTopActivityUncheckedLocked方法离钝,再調(diào)用ActivityStack的resumeTopActivityInnerLocked,最后進入到ActivityThread的scheduleLaunchActivity方法

前面講過可以啟動一個沒有在AndroidManifest.xml里面注冊過的Activity褪储,只需要用動態(tài)代理的方法卵渴,把H的handleMessage攔截,然后在這里把我們沒有注冊的Activity放回到intent里面就可以實現(xiàn)啟動沒有注冊的Activity



    public final class ActivityThread {

        public static void main(String[] args) {
            ...省略代碼
    
            // 下面是啟動UI主線程
            Looper.prepareMainLooper();
    
            ActivityThread thread = new ActivityThread();
            thread.attach(false);
    
            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();
            }
    
            if (false) {
                Looper.myLooper().setMessageLogging(new
                        LogPrinter(Log.DEBUG, "ActivityThread"));
            }
    
            // End of event ActivityThreadMain.
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            Looper.loop();
    
            throw new RuntimeException("Main thread loop unexpectedly exited");
        }

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

            ...
            // 發(fā)送啟動Activity的消息
            sendMessage(H.LAUNCH_ACTIVITY, r);
        }

    


        private class H extends Handler {
            ...省略代碼
            public void handleMessage(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;、

                    // 獲取Activity信息
                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break乱豆;
                    ...
                }
            }
            ...省略代碼
        }
        
        private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
            // If we are getting ready to gc after going to the background, well
            // we are back active so skip it.
            unscheduleGcIdler();
            mSomeActivitiesChanged = true;
    
            if (r.profilerInfo != null) {
                mProfiler.setProfiler(r.profilerInfo);
                mProfiler.startProfiling();
            }
    
            // Make sure we are running with the most recent config.
            handleConfigurationChanged(null, null);
    
            if (localLOGV) Slog.v(
                TAG, "Handling launch of " + r);
    
            // 初始化WindowManagerService服務(wù)
            WindowManagerGlobal.initialize();
    
            // 創(chuàng)建Activity,這里會執(zhí)行Activity的生命周期
            Activity a = performLaunchActivity(r, customIntent);
    
            // 如果Activity不為空奖恰,則啟動Activity
            if (a != null) {
                r.createdConfig = new Configuration(mConfiguration);
                reportSizeConfigurations(r);
                Bundle oldState = r.state;
                handleResumeActivity(r.token, false, r.isForward,
                        !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
    
                if (!r.activity.mFinished && r.startsNotResumed) {
                    // The activity manager actually wants this one to start out paused, because it
                    // needs to be visible but isn't in the foreground. We accomplish this by going
                    // through the normal startup (because activities expect to go through onResume()
                    // the first time they run, before their window is displayed), and then pausing it.
                    // However, in this case we do -not- need to do the full pause cycle (of freezing
                    // and such) because the activity manager assumes it can just retain the current
                    // state it has.
                    performPauseActivityIfNeeded(r, reason);
    
                    ...
                }
            } else {
                // 找不到需要啟動的Activity報錯
                // If there was an error, for any reason, tell the activity manager to stop us.
                try {
                    ActivityManagerNative.getDefault()
                        .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                                Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            }
        }
    }

這里只對Activity的啟動流程分析,沒有對每個方法進行詳情的分析宛裕,有興趣的讀者可以看Android的源碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市论泛,隨后出現(xiàn)的幾起案子揩尸,更是在濱河造成了極大的恐慌,老刑警劉巖屁奏,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岩榆,死亡現(xiàn)場離奇詭異,居然都是意外死亡坟瓢,警方通過查閱死者的電腦和手機勇边,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來折联,“玉大人粒褒,你說我怎么就攤上這事〕狭” “怎么了奕坟?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長清笨。 經(jīng)常有香客問我月杉,道長,這世上最難降的妖魔是什么抠艾? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任苛萎,我火速辦了婚禮,結(jié)果婚禮上检号,老公的妹妹穿的比我還像新娘腌歉。我一直安慰自己,他們只是感情好谨敛,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布究履。 她就那樣靜靜地躺著,像睡著了一般脸狸。 火紅的嫁衣襯著肌膚如雪最仑。 梳的紋絲不亂的頭發(fā)上藐俺,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音泥彤,去河邊找鬼欲芹。 笑死,一個胖子當(dāng)著我的面吹牛吟吝,可吹牛的內(nèi)容都是我干的菱父。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼剑逃,長吁一口氣:“原來是場噩夢啊……” “哼浙宜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蛹磺,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤粟瞬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后萤捆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體裙品,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年俗或,在試婚紗的時候發(fā)現(xiàn)自己被綠了市怎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡辛慰,死狀恐怖区匠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情昆雀,我是刑警寧澤辱志,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站狞膘,受9級特大地震影響揩懒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜挽封,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一已球、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧辅愿,春花似錦智亮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至癞埠,卻和暖如春状原,著一層夾襖步出監(jiān)牢的瞬間聋呢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工颠区, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留削锰,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓毕莱,卻偏偏與公主長得像器贩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子朋截,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

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