聊聊PhoneWindow特咆,getDecorView(),setContentView

前言

最近想實現(xiàn)一下滑動返回录粱,看了一下幾個開源的滑動返回的庫腻格,或多或少都有點問題画拾,就想自己做一下〔酥埃看了一下他們的源碼青抛,發(fā)現(xiàn)直接被activity.getWindow().getDecorView(),activity.getWindow().getDecorView().getChildAt(0),activity.findViewById(Window.ID_ANDROID_CONTENT)整蒙了酬核,它們具體代表一個界面的哪些區(qū)域蜜另。作為一個三年的Android開發(fā)我竟然說不清楚,好慚愧嫡意。今天就來總結(jié)一下PhoneWindow蚕钦,activity.getWindow().getDecorView(),statusBar鹅很,activity.findViewById(Window.ID_ANDROID_CONTENT)等等它們的邊邊角角嘶居,前生今生。

分析

先談?wù)剋indow促煮,PhoneWindow邮屁,getDecorView()
這里大部分參考自Android窗口機(jī)制(二)Window,PhoneWindow菠齿,DecorView佑吝,setContentView源碼理解

Window

它是一個抽象基類,代表頂級窗口的外觀及行為策略绳匀,這個類的一個實例應(yīng)該被用作添加到窗口管理器的頂層視圖芋忿。它提供了標(biāo)準(zhǔn)的UI策略,如背景疾棵,標(biāo)題區(qū)域戈钢,默認(rèn)密鑰處理等。
這個抽象類的唯一現(xiàn)有的實現(xiàn)是android.view.PhoneWindow是尔,當(dāng)你需要一個Window的時候你應(yīng)該實例化它殉了。

以上是官方描述,我的理解Window就是一個窗口拟枚,最直觀的表現(xiàn)就是一個界面的載體薪铜。

延伸一下:
那么Activity跟Window又是什么關(guān)系呢?Activity是我們開發(fā)app中打交道最多的一個類恩溅,它是一個用戶交互界面隔箍。那么它怎么是一個用戶交互界面呢?你不能說它是它就是脚乡,Activity的用戶交互體現(xiàn)在setContentView(@LayoutRes int layoutResID)方法蜒滩,布局xml文件就是界面展現(xiàn),有布局肯定就是有界面了。使用Activity的setContentView(@LayoutRes int layoutResID)將布局文件與Activity綁定帮掉,那么它是怎么綁定的,綁定到哪去了窒典?這里就要用到Window了蟆炊,Window是一個窗口,它有一個DecorView瀑志,而DecorView就是具體承載布局文件的view涩搓,后面具體分析

PhoneWindow

它是Window的唯一實現(xiàn)類,也就是說Window就是一個抽象劈猪,想要具體實現(xiàn)昧甘,具體操作還是要靠這個PhoneWindow

getDecorView()

這個方法在Window的源碼中

/**
 * Retrieve the top-level window decor view (containing the standard
 * window frame/decorations and the client's content inside of that), which
 * can be added as a window to the window manager.
 *
 * <p><em>Note that calling this function for the first time "locks in"
 * various window characteristics as described in
 * {@link #setContentView(View, android.view.ViewGroup.LayoutParams)}.</em></p>
 *
 * @return Returns the top-level window decor view.
 */
public abstract View getDecorView();

這個方法是獲取到頂層窗口的裝飾視圖(包含標(biāo)準(zhǔn)窗口框架/裝飾以及其內(nèi)部的客戶端內(nèi)容),可以將其作為窗口添加到窗口管理器战得。
那么什么是裝飾視圖DecorView呢充边,

/** @hide */
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
      ...
    DecorView(Context context, int featureId, PhoneWindow window,
            WindowManager.LayoutParams params) {
        super(context);
        mFeatureId = featureId;

        mShowInterpolator = AnimationUtils.loadInterpolator(context,
                android.R.interpolator.linear_out_slow_in);
        mHideInterpolator = AnimationUtils.loadInterpolator(context,
                android.R.interpolator.fast_out_linear_in);

        mBarEnterExitDuration = context.getResources().getInteger(
                R.integer.dock_enter_exit_duration);
        mForceWindowDrawsStatusBarBackground = context.getResources().getBoolean(
                R.bool.config_forceWindowDrawsStatusBarBackground)
                && context.getApplicationInfo().targetSdkVersion >= N;
        mSemiTransparentStatusBarColor = context.getResources().getColor(
                R.color.system_bar_background_semi_transparent, null /* theme */);

        updateAvailableWidth();

        setWindow(window);

        updateLogTag(params);

        mResizeShadowSize = context.getResources().getDimensionPixelSize(
                R.dimen.resize_shadow_size);
        initResizingPaints();
    }
      ...
}

在PhoneWindow里面,出現(xiàn)了成員變量DecorView常侦,它是一個window的頂層視圖浇冰,DecorView繼承于FrameLayout,我們那些標(biāo)題欄聋亡,內(nèi)容欄肘习,頂級上看是加載在DecorView上的。而DecorView則是由PhoneWindow負(fù)責(zé)添加坡倔。

setContentView

上面我們有個疑問漂佩,Activity的setContentView(@LayoutRes int layoutResID)將布局文件與Activity綁定,那么它是怎么綁定的罪塔,綁定到哪去了投蝉?這里我們就好好分析一下Activity的setContentView,說Activity是一個界面征堪,那只是抽象的描述墓拜,具體還是要體現(xiàn)在布局和view上。一個Activity包含一個Window请契,這個Window的實例化就是PhoneWindow咳榜,PhoneWindow中又有一個DecorView,DecorView繼承自FrameLayout爽锥,好了現(xiàn)在布局有了涌韩,往里面添加View那不就是布局和View都有了,那不就是可以組成一個完整的界面了氯夷。請看源碼娓娓道來
下面是Activity的setContentView

/**
     * Set the activity content from a layout resource.  The resource will be
     * inflated, adding all top-level views to the activity.
     *
     * @param layoutResID Resource ID to be inflated.
     *
     * @see #setContentView(android.view.View)
     * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
     */
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

指向的是Window的setContentView

/**
     * Convenience for
     * {@link #setContentView(View, android.view.ViewGroup.LayoutParams)}
     * to set the screen content from a layout resource.  The resource will be
     * inflated, adding all top-level views to the screen.
     *
     * @param layoutResID Resource ID to be inflated.
     * @see #setContentView(View, android.view.ViewGroup.LayoutParams)
     */
    public abstract void setContentView(@LayoutRes int layoutResID);

也就是PhoneWindow的具體實現(xiàn)

@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);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

我們看到當(dāng)mContentParent為null的時候會執(zhí)行installDecor()第一次進(jìn)來mContentParent肯定為null

private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            mDecor = generateDecor(-1);
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);

            // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
            mDecor.makeOptionalFitsSystemWindows();

            final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
                    R.id.decor_content_parent);

            if (decorContentParent != null) {
                mDecorContentParent = decorContentParent;
                mDecorContentParent.setWindowCallback(getCallback());
                if (mDecorContentParent.getTitle() == null) {
                    mDecorContentParent.setWindowTitle(mTitle);
                }

                final int localFeatures = getLocalFeatures();
                for (int i = 0; i < FEATURE_MAX; i++) {
                    if ((localFeatures & (1 << i)) != 0) {
                        mDecorContentParent.initFeature(i);
                    }
                }

                mDecorContentParent.setUiOptions(mUiOptions);

                if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
                        (mIconRes != 0 && !mDecorContentParent.hasIcon())) {
                    mDecorContentParent.setIcon(mIconRes);
                } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&
                        mIconRes == 0 && !mDecorContentParent.hasIcon()) {
                    mDecorContentParent.setIcon(
                            getContext().getPackageManager().getDefaultActivityIcon());
                    mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
                }
                if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
                        (mLogoRes != 0 && !mDecorContentParent.hasLogo())) {
                    mDecorContentParent.setLogo(mLogoRes);
                }

                // Invalidate if the panel menu hasn't been created before this.
                // Panel menu invalidation is deferred avoiding application onCreateOptionsMenu
                // being called in the middle of onCreate or similar.
                // A pending invalidation will typically be resolved before the posted message
                // would run normally in order to satisfy instance state restoration.
                PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
                if (!isDestroyed() && (st == null || st.menu == null) && !mIsStartingWindow) {
                    invalidatePanelMenu(FEATURE_ACTION_BAR);
                }
            } else {
                mTitleView = (TextView) findViewById(R.id.title);
                if (mTitleView != null) {
                    if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
                        final View titleContainer = findViewById(R.id.title_container);
                        if (titleContainer != null) {
                            titleContainer.setVisibility(View.GONE);
                        } else {
                            mTitleView.setVisibility(View.GONE);
                        }
                        mContentParent.setForeground(null);
                    } else {
                        mTitleView.setText(mTitle);
                    }
                }
            }
            ...
        }
    }

通過看installDecor的源碼我們發(fā)現(xiàn)臣樱,這個方法中做了兩件事:
生成DecorView
mDecor = generateDecor(-1);
和生成布局
mContentParent = generateLayout(mDecor);

protected DecorView generateDecor(int featureId) {
        // System process doesn't have application context and in that case we need to directly use
        // the context we have. Otherwise we want the application context, so we don't cling to the
        // activity.
        Context context;
        if (mUseDecorContext) {
            Context applicationContext = getContext().getApplicationContext();
            if (applicationContext == null) {
                context = getContext();
            } else {
                context = new DecorContext(applicationContext, getContext().getResources());
                if (mTheme != -1) {
                    context.setTheme(mTheme);
                }
            }
        } else {
            context = getContext();
        }
        return new DecorView(context, featureId, this, getAttributes());
    }

generateDecor這個方法我們不用多看,也沒什么東西,我們只需要知道生成一個DecorView的實例名字叫mDecor就行了

protected ViewGroup generateLayout(DecorView decor) {
       雇毫。玄捕。。

        // Inflate the window decor.

        int layoutResource;
        int features = getLocalFeatures();
        // System.out.println("Features: 0x" + Integer.toHexString(features));
        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
            layoutResource = R.layout.screen_swipe_dismiss;
        } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
            if (mIsFloating) {
                TypedValue res = new TypedValue();
                getContext().getTheme().resolveAttribute(
                        R.attr.dialogTitleIconsDecorLayout, res, true);
                layoutResource = res.resourceId;
            } else {
                layoutResource = R.layout.screen_title_icons;
            }
            // XXX Remove this once action bar supports these features.
            removeFeature(FEATURE_ACTION_BAR);
            // System.out.println("Title Icons!");
        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
                && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
            // Special case for a window with only a progress bar (and title).
            // XXX Need to have a no-title version of embedded windows.
            layoutResource = R.layout.screen_progress;
            // System.out.println("Progress!");
        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
            // Special case for a window with a custom title.
            // If the window is floating, we need a dialog layout
            if (mIsFloating) {
                TypedValue res = new TypedValue();
                getContext().getTheme().resolveAttribute(
                        R.attr.dialogCustomTitleDecorLayout, res, true);
                layoutResource = res.resourceId;
            } else {
                layoutResource = R.layout.screen_custom_title;
            }
            // XXX Remove this once action bar supports these features.
            removeFeature(FEATURE_ACTION_BAR);
        } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
            // If no other features and not embedded, only need a title.
            // If the window is floating, we need a dialog layout
            if (mIsFloating) {
                TypedValue res = new TypedValue();
                getContext().getTheme().resolveAttribute(
                        R.attr.dialogTitleDecorLayout, res, true);
                layoutResource = res.resourceId;
            } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
                layoutResource = a.getResourceId(
                        R.styleable.Window_windowActionBarFullscreenDecorLayout,
                        R.layout.screen_action_bar);
            } else {
                layoutResource = R.layout.screen_title;
            }
            // System.out.println("Title!");
        } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
            layoutResource = R.layout.screen_simple_overlay_action_mode;
        } else {
            // Embedded, so no decoration is needed.
            layoutResource = R.layout.screen_simple;
            // System.out.println("Simple!");
        }

        mDecor.startChanging();
        mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        if (contentParent == null) {
            throw new RuntimeException("Window couldn't find content container view");
        }

        if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
            ProgressBar progress = getCircularProgressBar(false);
            if (progress != null) {
                progress.setIndeterminate(true);
            }
        }

        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
            registerSwipeCallbacks();
        }

        // Remaining setup -- of background and title -- that only applies
        // to top-level windows.
        if (getContainer() == null) {
            final Drawable background;
            if (mBackgroundResource != 0) {
                background = getContext().getDrawable(mBackgroundResource);
            } else {
                background = mBackgroundDrawable;
            }
            mDecor.setWindowBackground(background);

            final Drawable frame;
            if (mFrameResource != 0) {
                frame = getContext().getDrawable(mFrameResource);
            } else {
                frame = null;
            }
            mDecor.setWindowFrame(frame);

            mDecor.setElevation(mElevation);
            mDecor.setClipToOutline(mClipToOutline);

            if (mTitle != null) {
                setTitle(mTitle);
            }

            if (mTitleColor == 0) {
                mTitleColor = mTextColor;
            }
            setTitleColor(mTitleColor);
        }

        mDecor.finishChanging();

        return contentParent;
    }

generateLayout這個方法里面的東西太多,我前面刪除一部分
這里layoutResource隙姿,是根據(jù)我們設(shè)置的狀態(tài)欄主題匈棘,判斷DecorView自動為我們加載什么樣的布局。當(dāng)我們將主題設(shè)置為NoTitleBar時馍迄,generateLayout方法中的layoutResource變量值為R.layout.screen_simple,所以我們看下系統(tǒng)這個screen_simple.xml布局文件

<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>

當(dāng)拿到這個layoutResource之后局骤,執(zhí)行的是mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

//DecorView的onResourcesLoaded方法
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
        mStackId = getStackId();

        if (mBackdropFrameRenderer != null) {
            loadBackgroundDrawablesIfNeeded();
            mBackdropFrameRenderer.onResourcesLoaded(
                    this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
                    mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
                    getCurrentColor(mNavigationColorViewState));
        }

        mDecorCaptionView = createDecorCaptionView(inflater);
        final View root = inflater.inflate(layoutResource, null);
        if (mDecorCaptionView != null) {
            if (mDecorCaptionView.getParent() == null) {
                addView(mDecorCaptionView,
                        new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
            }
            mDecorCaptionView.addView(root,
                    new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
        } else {

            // Put it below the color views.
            addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        }
        mContentRoot = (ViewGroup) root;
        initializeElevation();
    }

這里我們看到執(zhí)行了一下mDecorCaptionView = createDecorCaptionView(inflater);

// Free floating overlapping windows require a caption.
    private DecorCaptionView createDecorCaptionView(LayoutInflater inflater) {
        DecorCaptionView decorCaptionView = null;
        for (int i = getChildCount() - 1; i >= 0 && decorCaptionView == null; i--) {
            View view = getChildAt(i);
            if (view instanceof DecorCaptionView) {
                // The decor was most likely saved from a relaunch - so reuse it.
                decorCaptionView = (DecorCaptionView) view;
                removeViewAt(i);
            }
        }
        final WindowManager.LayoutParams attrs = mWindow.getAttributes();
        final boolean isApplication = attrs.type == TYPE_BASE_APPLICATION ||
                attrs.type == TYPE_APPLICATION || attrs.type == TYPE_DRAWN_APPLICATION;
        // Only a non floating application window on one of the allowed workspaces can get a caption
        if (!mWindow.isFloating() && isApplication && StackId.hasWindowDecor(mStackId)) {
            // Dependent on the brightness of the used title we either use the
            // dark or the light button frame.
            if (decorCaptionView == null) {
                decorCaptionView = inflateDecorCaptionView(inflater);
            }
            decorCaptionView.setPhoneWindow(mWindow, true /*showDecor*/);
        } else {
            decorCaptionView = null;
        }

        // Tell the decor if it has a visible caption.
        enableCaption(decorCaptionView != null);
        return decorCaptionView;
    }

上面的代碼我也沒看懂攀圈,但是看結(jié)果是mDecorCaptionView的創(chuàng)建結(jié)果還是空,當(dāng)mDecorCaptionView == null的時候會把我們加載出來的final View root = inflater.inflate(layoutResource, null);添加到DecorView的第0個位置峦甩,也就是一個FrameLayout視圖最下面赘来,就是是把剛才那個R.layout.screen_simple文件添加到DecorView最下面,也許看下面的Hierarchy View視圖更直觀一些,而且我們還看到了DecorView里面有一個LinearLayout并且index為0凯傲,細(xì)心的會發(fā)現(xiàn)DecorView還包含了NavigationBar View 還有StatusBar View撕捍,這些東西是什么時候加進(jìn)去的呢?這個先不管泣洞,也可以自己去看DecorView的源碼刨根問底忧风。


image.png

現(xiàn)在我們在拐回到剛才的generateLayout方法
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
其實就是執(zhí)行的getDecorView().findViewById,這個東西是誰呢球凰?就是前面加載的R.layout.screen_simple文件里面的FrameLayout android:id="@android:id/content"狮腿。最后contentParent作為generateLayout方法的返回賦值給mContentParent = generateLayout(mDecor);

/**
     * Finds a view that was identified by the id attribute from the XML that
     * was processed in {@link android.app.Activity#onCreate}.  This will
     * implicitly call {@link #getDecorView} for you, with all of the
     * associated side-effects.
     *
     * @return The view if found or null otherwise.
     */
    @Nullable
    public View findViewById(@IdRes int id) {
        return getDecorView().findViewById(id);
    }

寫了一大圈我們再回到PhoneWindow的setContentView(int layoutResID)方法,執(zhí)行mLayoutInflater.inflate(layoutResID, mContentParent);將我們Activity的R.layout.activity_main布局加載到mContentParent里面去呕诉,再看下面的圖也許會更清晰一些缘厢。

EF0FA9DD-9CAA-4BA2-BD0D-ED9BE3F3405C.png

回答幾個問題

現(xiàn)在來回答幾個疑問
1,activity.findViewById(Window.ID_ANDROID_CONTENT)拿到的是誰甩挫?
答:本文中拿到的是R.layout.sample布局文件的FrameLayout贴硫,其實根據(jù)不同的主題拿到不同的布局文件中的FrameLayout,它用來存放我們setContentView(id)時加載的布局
2伊者,activity.getWindow().getDecorView().getChildAt(0)拿到的是誰英遭?
答:本文中拿到的是R.layout.sample布局文件,其實根據(jù)不同的主題設(shè)置拿到不同的布局文件
3亦渗,statusBar在哪里挖诸?
答:在DecorView里面,可以去看上面的Hierarchy View視圖法精,也可以自己使用Hierarchy View看自己布局的視圖更直觀些多律。

參考文章

http://blog.csdn.net/fuuckwtu/article/details/6519689
http://blog.csdn.net/yanbober/article/details/45970721
http://blog.csdn.net/mr_liabill/article/details/49534851
http://www.reibang.com/p/983eb8d5bb1a
http://www.reibang.com/p/afa921d8ed24
http://blog.csdn.net/hohohong/article/details/54412464

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末痴突,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子狼荞,更是在濱河造成了極大的恐慌辽装,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件相味,死亡現(xiàn)場離奇詭異拾积,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)攻走,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來此再,“玉大人昔搂,你說我怎么就攤上這事∈淠矗” “怎么了摘符?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長策吠。 經(jīng)常有香客問我逛裤,道長,這世上最難降的妖魔是什么猴抹? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任带族,我火速辦了婚禮,結(jié)果婚禮上蟀给,老公的妹妹穿的比我還像新娘蝙砌。我一直安慰自己,他們只是感情好跋理,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布择克。 她就那樣靜靜地躺著,像睡著了一般前普。 火紅的嫁衣襯著肌膚如雪肚邢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天拭卿,我揣著相機(jī)與錄音骡湖,去河邊找鬼。 笑死峻厚,一個胖子當(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
  • 我被黑心中介騙來泰國打工主穗, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人毙芜。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓忽媒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親腋粥。 傳聞我的和親對象是個殘疾皇子晦雨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

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