View的onMeasure總結(jié)

前言

最近加了移動(dòng)開發(fā)前線的安卓學(xué)習(xí)群掂摔,看到他們?cè)谟懻搊nMeasure相關(guān)的內(nèi)容,于是寫個(gè)文章來學(xué)習(xí)和記錄一下onMeasure相關(guān)的內(nèi)容级历。

Activity的裝載過程

從Activity的setContentView方法切入

setContentView
    Window mWindow;
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }
attach

這里的getWindow()返回的是mWindow對(duì)象叭披。
關(guān)于這個(gè)Window對(duì)象,Activity在創(chuàng)建時(shí)嚼贡,會(huì)調(diào)用一個(gè)attach方法。

    final void attach(Context context, ActivityThread aThread,
                Instrumentation instr, IBinder token, int ident,
                Application application, Intent intent, ActivityInfo info,
                CharSequence title, Activity parent, String id,
                NonConfigurationInstances lastNonConfigurationInstances,
                Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
        ……
        mWindow = new PhoneWindow(this);
        mWindow.setCallback(this);
        ……
    }

Window類主要用來從WindowManagerService接收觸摸粤策、鍵盤等事件误窖,然后分發(fā)給Activity,并且Window類還承載了UI的顯示柔吼。Actiivty的Window實(shí)際上是個(gè)PhoneWindow對(duì)象吭服。
接著分析PhoneWindow.setContentView(id)。

    @Override
    public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }
        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        ……
    }
installDecor
    private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor();
            ……
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);
            ……
        }
    }

mDecor是一個(gè)DecorView對(duì)象蝌戒,DecorView繼承自FrameLayout沼琉。

generateLayout
    protected ViewGroup generateLayout(DecorView decor) {
        TypedArray a = getWindowStyle();
        
        if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
            requestFeature(FEATURE_NO_TITLE);
        } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
            // Don't allow an action bar if there is no title.
            requestFeature(FEATURE_ACTION_BAR);
        }
        int layoutResource;
        int features = getLocalFeatures();

        View in = mLayoutInflater.inflate(layoutResource, null);
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        mContentRoot = (ViewGroup) in;
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        
        return contentParent;
    }

generateDecor函數(shù)就簡(jiǎn)單地調(diào)用了DecorView的構(gòu)造函數(shù),generateLayout函數(shù)主要工作是根據(jù)Window的Features來決定要加載什么樣的布局文件友鼻,這里以R.layout.screen_simple這個(gè)布局文件為例子傻昙,這個(gè)布局文件位置在framework\core\res\res\layout目錄中妆档,具體布局文件如下虫碉。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">
    <ViewStub android:id="@+id/action_mode_bar_stub"
              android:inflatedId="@+id/action_mode_bar"
              android:layout="@layout/action_mode_bar"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:theme="?attr/actionBarTheme" />
    <FrameLayout
         android:id="@android:id/content"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:foregroundInsidePadding="false"
         android:foregroundGravity="fill_horizontal|top"
         android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

在generateLayout函數(shù)中,加載了布局文件之后须板,添加到了mDecor中兢卵,并且LayoutParams皆為MATCH_PARENT,mContentParent為id為android.R.id.content的FrameLayout。
繼續(xù)分析setContentView秽荤,在這個(gè)函數(shù)的后邊的地方調(diào)用了mLayoutInflater.inflate,把我們指定的布局文件加載到了mContentParent中。
至此贺嫂,我們可以大致的發(fā)現(xiàn),在一個(gè)簡(jiǎn)單的Activity中,真正的布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<DecorView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <FrameLayout
            android:id="@android:id/content"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <!-- This is where our layout is placed -->
        </FrameLayout>
    </LinearLayout>
</DecorView>
Activity啟動(dòng)過程

handleLaunchActivity->performLaunchActivity->和ActivityServiceManager交互->handleResumeActivity->performResumeActivity踱稍。

handleResumeActivity
    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
        ……
        ActivityClientRecord r = performResumeActivity(token, clearHide);

        if (r != null) {
            final Activity a = r.activity;

            ……
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }
            } else if (!willBeVisible) {
              ……
            }
            ……
        } 
    }

在handleResumeActivity方法中悠抹,把PhoneWindow中生成的DecorView添加到了WindowManager中。

WindowManagerImpl.addView
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }

mGlobal是一個(gè)WindowManagerGlobal對(duì)象啤挎。

WindowManagerGlobal.addView
public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        ViewRootImpl root;
        View panelParentView = null;
        ……
        synchronized (mLock) {
            // Start watching for system property changes.
            ……
            root = new ViewRootImpl(view.getContext(), display);
            ……
            view.setLayoutParams(wparams);
        
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }
        ……
        root.setView(view, wparams, panelParentView);
        
    }

在這個(gè)方法中新建了一個(gè)ViewRootImpl對(duì)象卵凑,并把DecorView對(duì)象傳入ViewRootImpl中,由ViewRootImpl來掌管整個(gè)視圖的measure勺卢,layout。

ViewRootImpl.getRootMeasureSpec
    private static int getRootMeasureSpec(int windowSize, int rootDimension) {
        int measureSpec;
        switch (rootDimension) {

        case ViewGroup.LayoutParams.MATCH_PARENT:
            // Window can't resize. Force root view to be windowSize.
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
            break;
        case ViewGroup.LayoutParams.WRAP_CONTENT:
            // Window can resize. Set max size for root view.
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
            break;
        default:
            // Window wants to be an exact size. Force root view to be that size.
            measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
            break;
        }
        return measureSpec;
    }

這個(gè)函數(shù)用來給DecorView賦MeasureSpec值宴抚,這個(gè)函數(shù)在measureHierarchy中被調(diào)用。

measureHierarchy
    private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
            final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
        int childWidthMeasureSpec;
        int childHeightMeasureSpec;
        boolean windowSizeMayChange = false;

        boolean goodMeasure = false;
        if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
            ……
        goodMeasure = true;
            ……
        }
        if (!goodMeasure) {
            childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
            childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
            performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
            if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
                windowSizeMayChange = true;
            }
        }
        return windowSizeMayChange;
    }

這個(gè)函數(shù)有個(gè)參數(shù)是WindowManager.LayoutParams菇曲,通過查看這個(gè)類可知,lp.width和lp.height都是match_parent弟胀,再結(jié)合getRootMeasureSpec函數(shù)蕊玷,可知,DecorView傳給子View的MeasureSpec是xxxdp+EXACTLY垃帅。

ViewGroup getChildMeasure方法
/**
     * Does the hard part of measureChildren: figuring out the MeasureSpec to
     * pass to a particular child. This method figures out the right MeasureSpec
     * for one dimension (height or width) of one child view.
     *
     * The goal is to combine information from our MeasureSpec with the
     * LayoutParams of the child to get the best possible results. For example,
     * if the this view knows its size (because its MeasureSpec has a mode of
     * EXACTLY), and the child has indicated in its LayoutParams that it wants
     * to be the same size as the parent, the parent should ask the child to
     * layout given an exact size.
     *
     * @param spec The requirements for this view
     * @param padding The padding of this view for the current dimension and
     *        margins, if applicable
     * @param childDimension How big the child wants to be in the current
     *        dimension
     * @return a MeasureSpec integer for the child
     */
    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
        int specMode = MeasureSpec.getMode(spec);
        int specSize = MeasureSpec.getSize(spec);

        int size = Math.max(0, specSize - padding);

        int resultSize = 0;
        int resultMode = 0;

        switch (specMode) {
        // Parent has imposed an exact size on us
        case MeasureSpec.EXACTLY:
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size. So be it.
                resultSize = size;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent has imposed a maximum size on us
        case MeasureSpec.AT_MOST:
            if (childDimension >= 0) {
                // Child wants a specific size... so be it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size, but our size is not fixed.
                // Constrain child to not be bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent asked to see how big we want to be
        case MeasureSpec.UNSPECIFIED:
            if (childDimension >= 0) {
                // Child wants a specific size... let him have it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size... find out how big it should
                // be
                resultSize = 0;
                resultMode = MeasureSpec.UNSPECIFIED;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size.... find out how
                // big it should be
                resultSize = 0;
                resultMode = MeasureSpec.UNSPECIFIED;
            }
            break;
        }
        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
    }

FrameLayout等ViewGroup子類在measure子View時(shí)方庭,會(huì)調(diào)用getChildMeasure方法,來決定子View的MeasureSpec械念。

總結(jié)
Parent的MeasureSpec 子View的LayoutParams 子View的MeasureSpec

</br>EXACTLY
</br>
xxxdp
</br>match_parent
</br>wrap_content
xxxdp + EXACTLY
</br>parent大小 + EXACTLY
</br> parent大小 + AT_MOST

</br>AT_MOST
</br>
xxxdp
</br>match_parent
</br>wrap_content
xxxdp + EXACTLY
</br>parent大小 + AT_MOST
</br> parent大小 + AT_MOST

</br>UNSPECIFIED
</br>
xxxdp
</br>match_parent
</br>wrap_content
xxxdp + EXACTLY
</br>0 + UNSPECIFIED
</br> 0 + UNSPECIFIED
DecorView的onMeasure函數(shù)

DecorView繼承自FrameLayout龄减,所以這里列出FrameLayout代碼

    /**
     * {@inheritDoc}
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int count = getChildCount();

        final boolean measureMatchParentChildren =
                MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
                MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
        mMatchParentChildren.clear();

        int maxHeight = 0;
        int maxWidth = 0;
        int childState = 0;

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (mMeasureAllChildren || child.getVisibility() != GONE) {
                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                maxWidth = Math.max(maxWidth,
                        child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
                maxHeight = Math.max(maxHeight,
                        child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
                childState = combineMeasuredStates(childState, child.getMeasuredState());
                if (measureMatchParentChildren) {
                    if (lp.width == LayoutParams.MATCH_PARENT ||
                            lp.height == LayoutParams.MATCH_PARENT) {
                        mMatchParentChildren.add(child);
                    }
                }
            }
        }

        // Account for padding too
        maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();
        maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();

        // Check against our minimum height and width
        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());

        // Check against our foreground's minimum height and width
        final Drawable drawable = getForeground();
        if (drawable != null) {
            maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
            maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
        }

        setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
                resolveSizeAndState(maxHeight, heightMeasureSpec,
                        childState << MEASURED_HEIGHT_STATE_SHIFT));

        count = mMatchParentChildren.size();
        if (count > 1) {
            for (int i = 0; i < count; i++) {
                final View child = mMatchParentChildren.get(i);

                final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
                int childWidthMeasureSpec;
                int childHeightMeasureSpec;
                
                if (lp.width == LayoutParams.MATCH_PARENT) {
                    childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() -
                            getPaddingLeftWithForeground() - getPaddingRightWithForeground() -
                            lp.leftMargin - lp.rightMargin,
                            MeasureSpec.EXACTLY);
                } else {
                    childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
                            getPaddingLeftWithForeground() + getPaddingRightWithForeground() +
                            lp.leftMargin + lp.rightMargin,
                            lp.width);
                }
                
                if (lp.height == LayoutParams.MATCH_PARENT) {
                    childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() -
                            getPaddingTopWithForeground() - getPaddingBottomWithForeground() -
                            lp.topMargin - lp.bottomMargin,
                            MeasureSpec.EXACTLY);
                } else {
                    childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
                            getPaddingTopWithForeground() + getPaddingBottomWithForeground() +
                            lp.topMargin + lp.bottomMargin,
                            lp.height);
                }

                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
            }
        }
    }

接下來驗(yàn)證我們的猜想希停,首先是DecorView署隘,這個(gè)Layout的MeasureSpec是xxxdp + EXACTLY,接著是LinearLayout,這個(gè)Layout獲得的MeasureSpec是 parent大小+EXACTLY磁餐。接著是FrameLayout,它的MeasureSpec也是parent大小+EXACTLY羞延,再接著就是我們的布局文件了。

TestView
public class TestView extends View{
    public TestView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int mode = MeasureSpec.getMode(widthMeasureSpec);
        int size = MeasureSpec.getSize(widthMeasureSpec);
        Log.d("xxj","size "+size);
        switch (mode){
            case MeasureSpec.EXACTLY:
                Log.d("xxj","mode exactly");
                break;
            case MeasureSpec.AT_MOST:
                Log.d("xxj","mode at_most");
                break;
            default:
                Log.d("xxj","mode unspecified");
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.netease.jnisample.TestView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

按照之前的猜想肴楷,F(xiàn)rameLayout獲得的MeasureSpec是parent大小 + EXACTLY荠呐。TestView獲得的MeasureSpec也應(yīng)該是parent大小+EXACTLY砂客。

運(yùn)行結(jié)果
運(yùn)行結(jié)果

接下來將TestView的width和height改為wrap_content呵恢,運(yùn)行結(jié)果應(yīng)為parent大小 + AT_MOST。

運(yùn)行結(jié)果

接下來將TestView的width和height改為50dp彤恶,結(jié)果應(yīng)為50dp + EXACTLY

運(yùn)行結(jié)果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鳄橘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子瘫怜,更是在濱河造成了極大的恐慌,老刑警劉巖鲸湃,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異笋除,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)垃它,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門烹看,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人听系,你說我怎么就攤上這事虹菲。” “怎么了毕源?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)址愿。 經(jīng)常有香客問我,道長(zhǎng)响谓,這世上最難降的妖魔是什么损合? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任嫁审,我火速辦了婚禮,結(jié)果婚禮上律适,老公的妹妹穿的比我還像新娘。我一直安慰自己捂贿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布厂僧。 她就那樣靜靜地躺著,像睡著了一般吁系。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上汽纤,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天福荸,我揣著相機(jī)與錄音,去河邊找鬼敬锐。 笑死,一個(gè)胖子當(dāng)著我的面吹牛台夺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播颤介,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼滚朵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起辕近,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎归粉,沒想到半個(gè)月后椿疗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盏浇,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年痒蓬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了滴劲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡班挖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出萧芙,到底是詐尸還是另有隱情,我是刑警寧澤双揪,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站渔期,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏疯趟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一信峻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧盹舞,春花似錦、人聲如沸矾策。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蓬豁。三九已至绰咽,卻和暖如春地粪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蟆技。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留质礼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓眶蕉,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親造挽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

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