android源碼--view創(chuàng)建原理總結(jié)

一忌穿、android界面構(gòu)成

android窗口組成.png

Activity:控制模型抒寂,控制Window掠剑。
Window:承載模型屈芜,負(fù)責(zé)承載視圖(View)。
View:顯示模型朴译,用于顯示井佑。
ViewRoot(ViewRootImpl):是連接WindowManager和DecorView的紐帶。

二眠寿、View創(chuàng)建整體流程總結(jié)

1躬翁、在ActivityThread的performLaunchActivity中調(diào)用Activity的attach方法,在attach方法中完成PhoneWindow的創(chuàng)建盯拱。
2盒发、在Activity的onCreate方法例嘱,setContentView方法,PhoneWindow中創(chuàng)建了一個DecorView宁舰,并在DecorView中填充了Activity中傳入的layoutId布局拼卵。通過LayoutInflater進(jìn)行布局文件的解析。DecorView蛮艰,它實(shí)際是一個FrameLayout腋腮,并通過各種主題樣式選擇加載不同的視圖來填充DecorView。
LayoutInflater一定要做成全局單例的方式壤蚜,原因很簡單就是為了加速view實(shí)例化的過程低葫,共用反射的構(gòu)造函數(shù)的緩存。
3仍律、在ActivityThread的handleResumeActivity中嘿悬,會調(diào)用WindowManager的addView方法將DecorView添加到WMS(WindowManagerService)上。addView找那個創(chuàng)建ViewRootImpl水泉,并通過ViewRootImpl的setView方法將view添加到WMS中善涨。
4、 在使用requestWindowFeature來設(shè)置樣式時草则,實(shí)際上是調(diào)用了PhoneWindow的requestFeature方法钢拧,會將樣式存儲在Window的mLocalFeatures變量中,當(dāng)installDecor時炕横,會應(yīng)用這些樣式源内。也就是說,當(dāng)需要通過requestWindowFeature來請求樣式時份殿,應(yīng)該在setContentView方法之前調(diào)用膜钓,因?yàn)閟etContentView方法的調(diào)用會導(dǎo)致DecorView的創(chuàng)建并應(yīng)用樣式,如果在之后調(diào)用則會導(dǎo)致不會生效卿嘲,因?yàn)榇藭rDecorView已經(jīng)創(chuàng)建完成了颂斜。

ViewRootImpl的setView方法中主要完成:View渲染(requestLayout)、(performTraservals)以及接收觸摸屏幕事件拾枣。設(shè)置了一系列輸入管道沃疮,將觸摸事件分發(fā)給DecorView。

三梅肤、View具體創(chuàng)建流程

1司蔬、PhoneWindow的創(chuàng)建

ActivityThread.java

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
···
Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.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);
            }
        } 
···
                Window window = null;
                if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }
                appContext.setOuterContext(activity);
                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, window, r.configCallback);
···
}

Activity.java

    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,
            Window window, ActivityConfigCallback activityConfigCallback) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);

        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            mWindow.setSoftInputMode(info.softInputMode);
        }
        if (info.uiOptions != 0) {
            mWindow.setUiOptions(info.uiOptions);
        }
        mUiThread = Thread.currentThread();

        mMainThread = aThread;
        mInstrumentation = instr;
        mToken = token;
···
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
    }

Activity在其attach方法中創(chuàng)建了Window塘雳,實(shí)際上創(chuàng)建的是PhoneWindow手报,并通過各種回調(diào)等建立起與Activity的聯(lián)系淘邻,我們在Activity中使用getWindow()所得到的即是這個創(chuàng)建的Window没隘。

2扬卷、setContentView (DecorView創(chuàng)建)

通常情況下蒲凶,一個Activity的界面的創(chuàng)建是通過setContentView來引入布局鹏倘。

mWindow = new PhoneWindow(this, window);

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

而Activity的setContentView方法是通過調(diào)用Window的setContentView方法刁愿,而Window是一個抽象對象,它的具體實(shí)現(xiàn)類就是PhoneWindow豪墅。在PhoneWindow中找到setContentView方法

@Override
public void setContentView(int layoutResID) {
     // 如果mContentParent為空時先構(gòu)建
   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 {
            // 通過LayoutInflater解析布局
       mLayoutInflater.inflate(layoutResID, mContentParent);
   }
   mContentParent.requestApplyInsets();
   final Callback cb = getCallback();
   if (cb != null && !isDestroyed()) {
       cb.onContentChanged();
   }
}

至此完成了在PhoneWindow中創(chuàng)建了一個DecorView泉手,并在DecorView中填充了Activity中傳入的layoutId布局。但還未被繪制到屏幕上偶器,這一步要到ActivityThread的handleResumeActivity時才會真正執(zhí)行斩萌。

通過LayoutInflater解析布局。主要通過inflate方法解析布局

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) 

上面的inflate方法所做的操作主要有以下幾步:

解析xml的根標(biāo)簽
如果根標(biāo)簽是merge屏轰,那么調(diào)用rInflate解析颊郎,將merge標(biāo)簽下的所有子View直接添加到根標(biāo)簽中
如果不是merge,調(diào)用createViewFromTag解析該元素
調(diào)用rInflate解析temp中的子View霎苗,并將這些子View添加到temp中
通過attachToRoot姆吭,返回對應(yīng)解析的根視圖

解析View的時候是通過.來判斷是內(nèi)置的View還是自定義的View的,那么我們就能知道為什么在寫布局文件中自定義的View需要完整路徑了唁盏。

public final View createView(String name, String prefix, AttributeSet attrs)
       throws ClassNotFoundException, InflateException {
   // 從緩存中獲取view的構(gòu)造函數(shù)
   Constructor<? extends View> constructor = sConstructorMap.get(name);
   if (constructor != null && !verifyClassLoader(constructor)) {
       constructor = null;
       sConstructorMap.remove(name);
   }
   Class<? extends View> clazz = null;

   try {
       Trace.traceBegin(Trace.TRACE_TAG_VIEW, name);
            // 如果沒有緩存
       if (constructor == null) {
           // 如果前綴不為空構(gòu)造完整的View路徑并加載該類
           clazz = mContext.getClassLoader().loadClass(
                   prefix != null ? (prefix + name) : name).asSubclass(View.class);
           // 獲取該類的構(gòu)造函數(shù)
           constructor = clazz.getConstructor(mConstructorSignature);
           constructor.setAccessible(true);
           // 將構(gòu)造函數(shù)加入緩存中
           sConstructorMap.put(name, constructor);
       } else {
       }

       Object[] args = mConstructorArgs;
       args[1] = attrs;
            // 通過反射構(gòu)建View
       final View view = constructor.newInstance(args);
       if (view instanceof ViewStub) {
           // Use the same context when inflating ViewStub later.
           final ViewStub viewStub = (ViewStub) view;
           viewStub.setLayoutInflater(cloneInContext((Context) args[0]));
       }
       return view;

   }
}

createView相對簡單内狸,通過判斷前綴,來構(gòu)建View的完整路徑厘擂,并將該類加載到虛擬機(jī)中昆淡,獲取構(gòu)造函數(shù)并緩存,再通過構(gòu)造函數(shù)創(chuàng)建該View對象刽严,并返回昂灵。這個時候我們就獲得了根視圖。接著調(diào)用rInflateChildren方法解析子View舞萄,并最終調(diào)用rInflate方法:

void rInflate(XmlPullParser parser, View parent, Context context,
       AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {

    // 獲取樹的深度眨补,通過深度優(yōu)先遍歷
   final int depth = parser.getDepth();
   int type;

   while (((type = parser.next()) != XmlPullParser.END_TAG ||
           parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {

       if (type != XmlPullParser.START_TAG) {
           continue;
       }

       final String name = parser.getName();
       
       if (TAG_REQUEST_FOCUS.equals(name)) {
           parseRequestFocus(parser, parent);
       } else if (TAG_TAG.equals(name)) {// 解析tag標(biāo)簽
           parseViewTag(parser, parent, attrs);
       } else if (TAG_INCLUDE.equals(name)) {// 解析include標(biāo)簽
           if (parser.getDepth() == 0) {
               throw new InflateException("<include /> cannot be the root element");
           }
           parseInclude(parser, context, parent, attrs);
       } else if (TAG_MERGE.equals(name)) {// 解析到merge標(biāo)簽,并報(bào)錯
           throw new InflateException("<merge /> must be the root element");
       } else {
            // 解析到普通的子View鹏氧,并調(diào)用createViewFromTag獲得View對象
           final View view = createViewFromTag(parent, name, context, attrs);
           final ViewGroup viewGroup = (ViewGroup) parent;
           final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
           // 遞歸解析
           rInflateChildren(parser, view, attrs, true);
           // 將View加入到父視圖中
           viewGroup.addView(view, params);
       }
   }

   if (finishInflate) {
       parent.onFinishInflate();
   }
}

http://www.reibang.com/p/c228e65ea1d9
http://www.reibang.com/p/427c59a70da6
https://blog.csdn.net/qq_28261343/article/details/78817184

3渤涌、View的顯示繪制

在ActivityThread的handleResumeActivity中佩谣,會調(diào)用WindowManager的addView方法將DecorView添加到WMS(WindowManagerService)上把还。
ActivityThread.java

    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
ActivityClientRecord r = mActivities.get(token);
        // 會調(diào)用activity的onResume方法
        r = performResumeActivity(token, clearHide, reason);

            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
//setContentView中完成的DecorView的創(chuàng)建
                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 (r.mPreserveWindow) {
                    a.mWindowAdded = true;
                    r.mPreserveWindow = false;
                    ViewRootImpl impl = decor.getViewRootImpl();
                    if (impl != null) {
                        impl.notifyChildRebuilt();
                    }
                }
                if (a.mVisibleFromClient && !a.mWindowAdded) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }

通過WindowManager的addView方法添加DecorView。WindowManager是一個接口茸俭,實(shí)際通過WindowManagerImpl進(jìn)行添加吊履。
WindowManagerImpl.java

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

WindowManagerGlobal.java

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        ViewRootImpl root;
        View panelParentView = null;
···
            //!5鼢蕖艇炎!創(chuàng)建ViewRootImpl
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        try {
            root.setView(view, wparams, panelParentView);
        }
}

通過ViewRootImpl的setView方法將view添加到WMS中

ViewRootImpl.java

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
     //  會調(diào)用scheduleTraversals()方法腾窝,后續(xù)會執(zhí)行measure-layout-draw缀踪?確保View在添加到Window上顯示到屏幕之前居砖,已完成測量和繪制操作。
                  requestLayout();
        ···
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } 
}

requestLayout執(zhí)行布局刷新驴娃,調(diào)用mWindowSession的方法將View添加到WMS中奏候。
最終通過Binder,遠(yuǎn)程調(diào)用WMS中的addToDisplay完成View的添加唇敞。

ViewRootImpl的setView方法中主要完成:View渲染(requestLayout)以及接收觸摸屏幕事件蔗草。設(shè)置了一系列輸入管道,將觸摸事件分發(fā)給DecorView疆柔。

ViewRootImpl.java

    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }

    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//mChoreographer.postCallback主要邏輯是向Handler發(fā)送一個異步消息咒精,然后在mTraversalRunnable(是Runnable對象)中處理          
mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }

    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
        ...
            performTraversals();//執(zhí)行真正的view繪制流程measure-->layout-->draw
      ...
        }
    }

四、ViewRootImpl

ViewRoot是一個ViewTree的管理者旷档,而不是ViewTree的根節(jié)點(diǎn)模叙。
嚴(yán)格意義上說,ViewTree的根節(jié)點(diǎn)只有DecorView鞋屈。
ViewRoot將DecorView和PhoneWindow(Activity創(chuàng)建的Window實(shí)例)“組合”起來向楼。

View的繪制三大流程(measure,layout谐区,draw)均是通過ViewRootImpl來完成的湖蜕。
在ActivityThread中,當(dāng)Activity對象被創(chuàng)建完畢后宋列,會將DecorVidew添加到Window中昭抒,同時會創(chuàng)建ViewRootImpl對象,利用ViewRootImpl對象來建立Window對象和DecorView之間的關(guān)系炼杖。

View的繪制是從ViewRootImlp的performTraversals開始的灭返,經(jīng)過measure.layout.draw三方法最終將一個View繪制出來。measure測量View寬高坤邪。layout確定View位置熙含,draw負(fù)責(zé)繪制。

window持有DecorView,DecorView在被添加到window到時候艇纺,會產(chǎn)生一個ViewRootImlp怎静,ViewRootImlp在調(diào)用performTraversals(遍歷表演)的時候會調(diào)用頂級view的測量,布局和繪制黔衡,然后頂級view會挨個調(diào)用自己子布局的測量布局和繪制蚓聘,這樣一個頁面就展現(xiàn)出來了。

五盟劫、 attachWindow和 detachWindow

attach流程
當(dāng)在ActivityThread.handleResumeActivity()方法中調(diào)用WindowManager.addView()方法時夜牡,最終是調(diào)去了

WindowManagerImpl.addView() -->
WindowManagerGlobal.addView()
ViewRootImpl.setView()
ViewRootImpl.performTraversals()
host.dispatchAttachedToWindow(mAttachInfo, 0)
//ViewGroup和View有不同實(shí)現(xiàn),ViewGroup依次分發(fā)到子View

detach流程

ActivityThread.handleDestroyActivity() -->
WindowManager.removeViewImmediate() -->
WindowManagerGlobal.removeViewLocked()方法 —>
ViewRootImpl.die() --> doDie() -->
ViewRootImpl.dispatchDetachedFromWindow()

1侣签、onAttachedToWindow方法是在Activity resume的時候被調(diào)用的塘装,也就是act對應(yīng)的window被添加的時候急迂,且每個view只會被調(diào)用一次,父view的調(diào)用在前蹦肴,不論view的visibility狀態(tài)都會被調(diào)用袋毙,適合做些view特定的初始化操作;
2冗尤、onDetachedFromWindow方法是在Activity destroy的時候被調(diào)用的听盖,也就是act對應(yīng)的window被刪除的時候,且每個view只會被調(diào)用一次裂七,父view的調(diào)用在后皆看,也不論view的visibility狀態(tài)都會被調(diào)用,適合做最后的清理操作背零;
3腰吟、這些結(jié)論也正好解釋了方法名里帶有window的原因,有些人可能會想徙瓶,那為啥不叫onAttachedToActivity/onDetachedFromActivity毛雇,因?yàn)樵贏ndroid里不止是Activity,這里說的內(nèi)容同樣適用于Dialog/Toast侦镇,Window只是個虛的概念灵疮,是Android抽象出來的,最終操作的實(shí)體還是View壳繁,這也說明了前面的WindowManager接口為啥是從ViewManager接口派生的震捣,因?yàn)樗幸磺械幕瘹w根結(jié)底還是對View的操作。

http://www.reibang.com/p/e7b6fa788ae6

六闹炉、Token及其他窗口

1蒿赢、Token是什么?
類型為IBinder渣触,是一個Binder對象羡棵。
主要分兩種Token:
指向Window的token: 主要是實(shí)現(xiàn)WmS和應(yīng)用所在進(jìn)程通信。
指向ActivityRecord的token: 主要是實(shí)現(xiàn)WMS和AMS通信的嗅钻。

2皂冰、Token的使用場景?
Activity創(chuàng)建時啊犬,AMS中需要根據(jù)Token去找到對應(yīng)的ActivityRecord灼擂。
Popupwindow的showAtLocation第一個參數(shù)需要傳入View,這個View就是用來獲取Token的觉至。

3、WindowSession是什么
在WindowManager的addView中會創(chuàng)建ViewRootImpl睡腿,內(nèi)部會通過WMS去獲取WindowSession
WindowSession的類型是IWindowSession语御,本身是Binder對象峻贮,真正實(shí)現(xiàn)類是Session。

WindowManager.LayoutParams上有三種窗口類型type应闯,對應(yīng)為:
應(yīng)用程序窗口:type值在 FIRST_APPLICATION_WINDOW LAST_APPLICATION_WINDOW 須將token設(shè)置成Activity的token纤控。
eg: Activity窗口,Dialog

子窗口: type值在 FIRST_SUB_WINDOW ~ LAST_SUB_WINDOW SubWindows與頂層窗口相關(guān)聯(lián),需將token設(shè)置成它所附著宿主窗口的token碉纺。
eg: PopupWindow(想要依附在Activity上需要將token設(shè)置成Activity的token)

系統(tǒng)窗口 : type值在 FIRST_SYSTEM_WINDOW ~ LAST_SYSTEM_WINDOW SystemWindows不能用于應(yīng)用程序船万,使用時需要有特殊權(quán)限,它是特定的系統(tǒng)功能才能使用骨田。
eg: Toast耿导,輸入法等

token是用來表示窗口的一個令牌态贤,只有符合條件的token才能被WMS通過添加到應(yīng)用上舱呻。
http://www.reibang.com/p/bac61386d9bf

參考

http://www.reibang.com/p/c228e65ea1d9
http://www.reibang.com/p/427c59a70da6
https://blog.csdn.net/qq_28261343/article/details/78817184
http://www.reibang.com/p/9da7bfe18374
http://www.reibang.com/p/e7b6fa788ae6
http://www.reibang.com/p/bac61386d9bf

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市悠汽,隨后出現(xiàn)的幾起案子箱吕,更是在濱河造成了極大的恐慌,老刑警劉巖柿冲,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茬高,死亡現(xiàn)場離奇詭異,居然都是意外死亡假抄,警方通過查閱死者的電腦和手機(jī)雅采,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來慨亲,“玉大人婚瓜,你說我怎么就攤上這事⌒炭茫” “怎么了巴刻?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蛉签。 經(jīng)常有香客問我胡陪,道長,這世上最難降的妖魔是什么碍舍? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任柠座,我火速辦了婚禮,結(jié)果婚禮上片橡,老公的妹妹穿的比我還像新娘妈经。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布吹泡。 她就那樣靜靜地躺著骤星,像睡著了一般。 火紅的嫁衣襯著肌膚如雪爆哑。 梳的紋絲不亂的頭發(fā)上洞难,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機(jī)與錄音揭朝,去河邊找鬼队贱。 笑死,一個胖子當(dāng)著我的面吹牛潭袱,可吹牛的內(nèi)容都是我干的柱嫌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼敌卓,長吁一口氣:“原來是場噩夢啊……” “哼慎式!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起趟径,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤瘪吏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蜗巧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掌眠,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年幕屹,在試婚紗的時候發(fā)現(xiàn)自己被綠了蓝丙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡望拖,死狀恐怖渺尘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情说敏,我是刑警寧澤鸥跟,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站盔沫,受9級特大地震影響医咨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜架诞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一拟淮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谴忧,春花似錦很泊、人聲如沸角虫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽上遥。三九已至搏屑,卻和暖如春争涌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辣恋。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工亮垫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人伟骨。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓饮潦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親携狭。 傳聞我的和親對象是個殘疾皇子继蜡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353

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