對(duì)Android中View的post方法進(jìn)行探索

ps:源碼是基于 android api 27 來(lái)分析的克锣,demo 是用 kotlin 語(yǔ)言寫(xiě)的。

Android 中蕊程,如果在ActivityonCreate 方法直接獲取View 的寬高是獲取不到的,但如果是調(diào)用 Viewpost方法通過(guò)它(post方法)參數(shù)Runnable 接口的回調(diào)卻能夠獲取到 View 的寬高袜腥,Viewpost 方法是馬上執(zhí)行的嗎肩狂?它的執(zhí)行時(shí)機(jī)又是什么時(shí)候呢摘完?下面我們舉個(gè)例子驗(yàn)證一下以下幾點(diǎn):

  1. post方法中的Runnable接口的回調(diào)能否直接獲取View的寬;
  2. post方法中Runnable接口的回調(diào)和ActivityonResume方法的先后順序;
  3. ActivityonResume方法能否直接獲取View的寬;
  4. View沒(méi)有被添加到Window里的時(shí)候姥饰,執(zhí)行post方法,Runnable接口能否被回調(diào)傻谁。

PostDemo

(1)新建一個(gè) Kotlin 類(lèi)型的類(lèi)MyView 并繼承于View

class MyView: View {
    constructor(context: Context): super(context) {
    }

    constructor(context: Context,@Nullable attrs: AttributeSet): super(context,attrs) {}

    constructor(context: Context,@Nullable attrs: AttributeSet,defStyleAttr: Int): super(context,attrs,defStyleAttr) { }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        Log.d(MainActivity.TAG,"------onMeasure--")
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
        Log.d(MainActivity.TAG,"------onLayout--")
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        Log.d(MainActivity.TAG,"------onDraw--")
    }
}

(2)新建一個(gè) Kotlin 語(yǔ)言類(lèi)型的Activity,名叫MainActivity

class MainActivity: AppCompatActivity() {
    companion object {
        var TAG: String = "MainActivity"
    }
    var mView: View? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mView = findViewById(R.id.my_view);
        mView?.post(Runnable {
             Log.d(TAG,"在 post 方法中獲取 View 的寬--" + mView?.getWidth())
        })
    }

    override fun onResume() {
        super.onResume()
        Log.d(TAG,"----onResume---")
        Log.d(TAG,"在 onResume 方法中獲取 View 的寬--" + mView?.getWidth())
    }
}

(3)MainActivity的布局界面activity_main.xml如下所示:

<?xml version="1.0" encoding="utf-8"?>
<com.xe.postdemo.MyView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/my_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FF0000"
    tools:context="com.xe.postdemo.MainActivity">
</com.xe.postdemo.MyView>

把程序運(yùn)行一下列粪,日志打印如下所示:

08-28 08:54:24.364 10133-10133/com.xe.postdemo D/MainActivity: ----onResume---
08-28 08:54:24.364 10133-10133/com.xe.postdemo D/MainActivity: 在 onResume 方法中獲取 View 的寬--0
08-28 08:54:24.435 10133-10133/com.xe.postdemo D/MainActivity: ------onMeasure--
08-28 08:54:24.487 10133-10133/com.xe.postdemo D/MainActivity: ------onMeasure--
08-28 08:54:24.490 10133-10133/com.xe.postdemo D/MainActivity: ------onLayout--
08-28 08:54:24.501 2285-2738/? D/Launcher.AllAppsList: updatePackage, find appInfo=AppInfo, id=-1, itemType=0, user=UserHandle{0}, mIconType=0, pkgName=com.xe.postdemo, className=com.xe.postdemo.MainActivity, screenId=-1, container=-1, cellX=-1, cellY=-1, spanX=1, spanY=1, isLandscapePos=false from ComponentInfo{com.xe.postdemo/com.xe.postdemo.MainActivity}
08-28 08:54:24.505 2285-2738/? D/Launcher.Model: onReceiveBackground, mAllAppsList=add=[], remove=[], modified=[(0, AppInfo, id=-1, itemType=0, user=UserHandle{0}, mIconType=0, pkgName=com.xe.postdemo, className=com.xe.postdemo.MainActivity, screenId=-1, container=-1, cellX=-1, cellY=-1, spanX=1, spanY=1, isLandscapePos=false)]
08-28 08:54:24.542 10133-10133/com.xe.postdemo D/MainActivity: ------onDraw--
08-28 08:54:24.714 1472-1555/? I/Timeline: Timeline: Activity_windows_visible id: ActivityRecord{afbc1c9 u0 com.xe.postdemo/.MainActivity t7087} time:4018603
08-28 08:54:24.715 1472-1530/? I/ActivityManager: Displayed com.xe.postdemo/.MainActivity: +4s904ms
08-28 08:54:24.762 10133-10133/com.xe.postdemo D/MainActivity: 在 post 方法中獲取 View 的寬--720

從日志可以看出:
post方法中Runnable 接口的回調(diào)中是可以直接獲取到View 的审磁;
ActivityonResume 方法比post 方法中Runnable 接口的回調(diào)先執(zhí)行,post方法中Runnable 接口是在View 的繪制(主要是ViewonMeasure岂座、onLayoutonDraw 方法)之后才會(huì)被回調(diào)态蒂;
ActivityonResume 方法不能直接獲取View 的寬,因?yàn)?code>Activity 的onResume 方法比ViewonMeasureonLayout 方法先執(zhí)行费什。

好钾恢,我們把MainActivityonCreate 方法做一下修改,其他不變:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
//        setContentView(R.layout.activity_main)
//        mView = findViewById(R.id.my_view);
        mView = MyView(this)
        mView?.post(Runnable {
             Log.d(TAG,"在 post 方法中獲取 View 的寬--" + mView?.getWidth())
        })
}

運(yùn)行程序鸳址,日志打印如下所示:

08-31 13:24:02.481 10794-10794/com.xe.postdemo D/MainActivity: ----onResume---
08-31 13:24:02.481 10794-10794/com.xe.postdemo D/MainActivity: 在 onResume 方法中獲取 View 的寬--0

從日志可以看出:
View沒(méi)有被添加到Window里的時(shí)候瘩蚪,執(zhí)行post方法,Runnable接口不會(huì)被回調(diào)稿黍。

好了疹瘦,以上驗(yàn)證的4點(diǎn)以及Viewpost方法執(zhí)行時(shí)機(jī)可以從源碼中找到原因,我們先從Viewpost方法看起巡球;

public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }

        // Postpone the runnable until we know on which thread it needs to run.
        // Assume that the runnable will be successfully placed after attach.
        getRunQueue().post(action);
        return true;
}

這里attachInfo 是為空的言沐,所以不會(huì)執(zhí)行 attachInfo.mHandler.post(action)這行代碼,我們看 getRunQueue().post(action)這行代碼酣栈,getRunQueue() 方法得到的是一個(gè)HandlerActionQueue 類(lèi)型的對(duì)象险胰,我們點(diǎn)擊HandlerActionQueuepost方法查看;

public void post(Runnable action) {
    postDelayed(action, 0);
}

HandlerActionQueuepost方法又調(diào)用了自己的postDelayed方法矿筝,這里的參數(shù)0表示延時(shí)所有的事件起便,我們往下看HandlerActionQueuepostDelayed方法;

public void postDelayed(Runnable action, long delayMillis) {
        final HandlerAction handlerAction = new HandlerAction(action, delayMillis);

        synchronized (this) {
            if (mActions == null) {
                mActions = new HandlerAction[4];
            }
            mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
            mCount++;
        }
}

從這個(gè)方法看出:HandlerAction表示要執(zhí)行的任務(wù)跋涣,要執(zhí)行的任務(wù)HandlerAction保存在數(shù)組長(zhǎng)度為4的mActions數(shù)組中缨睡,mCount表示數(shù)組mActions的下標(biāo),每次都加1陈辱;這個(gè)postDelayd方法并沒(méi)有馬上執(zhí)行任務(wù)奖年,而是保存了任務(wù),那么執(zhí)行任務(wù)的語(yǔ)句在哪里呢沛贪?

有時(shí)候我們會(huì)說(shuō)看到Activity的界面后 onResume方法就會(huì)被回調(diào)陋守,所以我們從調(diào)用ActivityonResume方法的AcitivityThread.handleResumeActivity方法說(shuō)起震贵;

final void handleResumeActivity(IBinder token,
                                    boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        ......
        //1、
        // TODO Push resumeArgs into the activity for consideration
        r = performResumeActivity(token, clearHide, reason);
        if (r != null) {
            ......
            if (!r.activity.mFinished && willBeVisible
                 ......
                if (r.activity.mVisibleFromClient) {
                    //2水评、
                    r.activity.makeVisible();
                }
            }
            ......
        } else {
            ......
        }
 }

這里的注釋1 最終會(huì)調(diào)用ActivityonResume方法猩系,
我們往下看注釋2 的代碼,它是ActivitymakeVisible方法:

void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            
            //3中燥、
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
}

注釋3 表示將View視圖添加到ViewManager中寇甸,我們點(diǎn)擊注釋3 的代碼進(jìn)去看看,ViewManager的實(shí)現(xiàn)類(lèi)是WindowManagerImpl疗涉,所以我們看的是WindowManagerImpladdView方法:

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

注釋4 處調(diào)用了WindowManagerGlobaladdView方法,我們往下看咱扣;

public void addView(View view, ViewGroup.LayoutParams params,
                        Display display, Window parentWindow) {
        ......
        synchronized (mLock) {
            ......
            //5绽淘、
            root = new ViewRootImpl(view.getContext(), display);
            ......
            try {
                //6、
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
               ......
            }
        }
}

我們點(diǎn)擊注釋5 的代碼闹伪,看看ViewRootImpl的構(gòu)造方法沪铭;

public ViewRootImpl(Context context, Display display) {
        ......
        //7、
        mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
                context);
        ......
 }

一剛開(kāi)始的時(shí)候偏瓤,我們?cè)?code>Activity的onCreate方法中先執(zhí)行View.post方法杀怠,但是ViewRootImplActivityonResume方法之后才會(huì)被初始化,還順便在ViewRootImpl的構(gòu)造方法中初始化AttachInfo硼补,所以說(shuō)一開(kāi)始View.post方法中的attachInfo就為null驮肉,從而執(zhí)行getRunQueue().post(action)語(yǔ)句;
我們往下看注釋6 的代碼已骇,也就是ViewRootImplsetView方法离钝;

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                //8、
                mView = view;
                ......
                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                //9褪储、
                requestLayout();
                ......
            }
        }
}

這里注釋8 的View是底部容器DecorView卵渴;
我們繼續(xù)往下看注釋9 的方法,也就是ViewRootImplrequestLayout方法鲤竹;

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

requestLayout方法調(diào)用了ViewRootImplscheduleTraversals方法浪读,我們且看scheduleTraversals方法;

void scheduleTraversals() {
        if (!mTraversalScheduled) {
            ......
            //10辛藻、
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            //11碘橘、
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            ......
        }
}

注釋10 這里先不說(shuō),后面再說(shuō)吱肌,
注釋11 的代碼會(huì)回調(diào)mTraversalRunnable對(duì)象痘拆,而mTraversalRunnable對(duì)象是一個(gè)Runnable接口的實(shí)現(xiàn)類(lèi)TraversalRunnable具體的對(duì)象,mTraversalRunnable對(duì)象又調(diào)用了ViewRootImpldoTraversal方法氮墨,doTraversal方法又調(diào)用了ViewRootImplperformTraversals方法纺蛆,我們來(lái)看看performTraversals方法:

private void performTraversals() {
        //12
        // cache mView since it is used so much below...
        final View host = mView;
        ......
        if (mFirst) {
            ......
            //13吐葵、
            host.dispatchAttachedToWindow(mAttachInfo, 0);
            ......
        } else {
            ......
        }
        ......
        if (mFirst || windowShouldResize || insetsChanged ||
                viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
            mForceNextWindowRelayout = false;
            ......
            if (!mStopped || mReportNextDraw) {
                    ......
                    //14、
                    // Ask host how big it wants to be
                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                    ......
            }
        } else {
            ......
        }
        ......
        if (didLayout) {
            //15桥氏、
            performLayout(lp, mWidth, mHeight);
            ......
        }
        ......
        if (!cancelDraw && !newSurface) {
            ......
            //16温峭、
            performDraw();
        } else {
            ......
        }
        ......
}

注釋12 就是上面注釋8 中說(shuō)的底部容器DecorView
注釋13 表示DecorView關(guān)聯(lián)AttachInfo字支,dispatchAttachedToWindow方法是在ViewGroup 里實(shí)現(xiàn)凤藏,該方法會(huì)遍歷DecorView 的子元素進(jìn)行 關(guān)聯(lián)AttachInfo,我們看一下ViewGroupdispatchAttachedToWindow 方法:

    @Override
    void dispatchAttachedToWindow(AttachInfo info, int visibility) {
        ......
        for (int i = 0; i < count; i++) {
            final View child = children[i];
            
            //17祥款、
            child.dispatchAttachedToWindow(info,
                    combineVisibility(visibility, child.getVisibility()));
        }
        ......
    }

這個(gè)方法是很重要的:
子元素關(guān)聯(lián)了AttachInfo清笨,然后將之前 View.post 保存的任務(wù)添加到AttachInfo 內(nèi)部的Handler,所以View 沒(méi)有被添加到Window 里的時(shí)候刃跛,執(zhí)行post 方法,Runnable接口沒(méi)有被回調(diào)苛萎;
我們看注釋17 的代碼桨昙,它是ViewdispatchAttachedToWindow 方法;

void dispatchAttachedToWindow(AttachInfo info, int visibility) {
        ......
        // Transfer all pending runnables.
        if (mRunQueue != null) {
            //18腌歉、
            mRunQueue.executeActions(info.mHandler);
            mRunQueue = null;
        }
        ......
 }

注釋18 的代碼表示調(diào)用了HandlerActionQueueexecuteActions 方法蛙酪,我們來(lái)看看executeActions 方法;

public void executeActions(Handler handler) {
        synchronized (this) {
            final HandlerAction[] actions = mActions;
            for (int i = 0, count = mCount; i < count; i++) {
                final HandlerAction handlerAction = actions[i];

                //19翘盖、
                handler.postDelayed(handlerAction.action, handlerAction.delay);
            }

            //20桂塞、
            mActions = null;
            mCount = 0;
        }
}

注釋19 行的代碼我們先留下懸念;
注釋20 是將mActions 置空馍驯,從第二次調(diào)用 View.post 開(kāi)始阁危,Runnable會(huì)被添加到AttachInfo 內(nèi)部的Handler,而不是HandlerAction汰瘫,ViewonMeasure狂打、onLayoutonDraw 方法也不會(huì)被調(diào)用;
我們回過(guò)頭來(lái)看注釋14 的代碼混弥,也就是ViewRootImplperformMeasure 方法趴乡;

private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
        ......
        try {
            
            //21、
            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
}

注釋21 的mView 表示DecorView蝗拿,它的measure 方法是在View 里晾捏,我們來(lái)看一下Viewmeasure 方法;

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
        ......
        if (forceLayout || needsLayout) {
           ......
            if (cacheIndex < 0 || sIgnoreMeasureCache) {
                // measure ourselves, this should set the measured dimension flag back
                //22哀托、
                onMeasure(widthMeasureSpec, heightMeasureSpec);
                mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
            } else {
                ......
            }
            ......
        }
        ......
}

注釋22 的代碼是調(diào)用的是DecorViewonMeasure 方法惦辛,而不是ViewonMeasure 方法,我們往下看DecorViewonMeasure 方法萤捆;

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        ......
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        ......
    }

DecorViewonMeasure 方法調(diào)用了 父類(lèi)的onMeasure 方法裙品,最終的實(shí)現(xiàn)是在FrameLayoutmeasure 方法:

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        ......
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (mMeasureAllChildren || child.getVisibility() != GONE) {
                
                //23俗批、
                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
                ......
            }
        }
        ......
    }

注釋23 的代碼會(huì)對(duì)所有子View 進(jìn)行了一遍測(cè)量,并計(jì)算出所有子 View 的最大寬度和最大高度市怎,我們往下看FrameLayoutmeasureChildWithMargins 方法岁忘;

    protected void measureChildWithMargins(View child,
                                           int parentWidthMeasureSpec, int widthUsed,
                                           int parentHeightMeasureSpec, int heightUsed) {
        ......
        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

我們假設(shè)child 是具體的View,而不是ViewGroup区匠,Viewmeasure 方法最終調(diào)用了ViewonMeasure 方法干像,onMeasure方法最終是測(cè)量View 的寬高;
我們回過(guò)頭來(lái)看:注釋15 的代碼最終會(huì)調(diào)用 View.onLayout 方法驰弄,它的調(diào)用過(guò)程是:
ViewRootImpl.performLayout-> host.layout(ViewGroup.layout)->super.layout(View.layout)-> View.onLayout麻汰,
最終完成View 位置的確定;

注釋16 的代碼最終會(huì)調(diào)用 View.onDraw 方法戚篙,它的調(diào)用過(guò)程是 :ViewRootImpl.performDraw -> ViewRootImpl.draw->ViewRootImpl.drawSoftware-> mView.draw(DecorView.draw)->super.draw(View.draw)-> View.onDraw五鲫,
最終完成 View 的繪畫(huà)出來(lái);

好了岔擂,現(xiàn)在我們可以解答上面剩下的疑問(wèn)了位喂,AcitivityThread.handleResumeActivity方法 先調(diào)用自己的performResumeActivity 方法,而該方法最終調(diào)用ActivityonResume 方法乱灵,而后再調(diào)用ActivitymakeVisible 方法塑崖,ActivitymakeVisible 方法最終完成View 的測(cè)量寬高、位置確定和繪畫(huà)痛倚,所以ActivityonResume 方法不能直接獲取View 的寬规婆。

我們?cè)诨剡^(guò)頭來(lái)看,注釋19 的代碼蝉稳,它的延時(shí)時(shí)間為0啊抒蚜,而且比 View 的onMeasureonLayoutonDraw 方法先被調(diào)用啊颠区,為什么從上面的demo 日志看出最終Runnable 接口等ViewonMeasure削锰、onLayoutonDraw 方法調(diào)用完之后再調(diào)用?
是因?yàn)樽⑨?0 的代碼先比注釋19 的代碼先被調(diào)用毕莱,注釋10 表示開(kāi)啟了同步消息屏障器贩,Android中它有一個(gè)異步消息優(yōu)先級(jí)比較高的權(quán)利,保障 View 繪制完后再給其他消息執(zhí)行朋截,所以在 View.post方法中的Runnable 接口的回調(diào)能直接獲取View 的寬蛹稍。

ActivityonResume 方法是在ActivitymakeVisible 方法先被調(diào)用的,而ViewpostRunnable 接口是在View 繪制完才會(huì)被回調(diào)的部服,所以ActivityonResume 方法先比 View.post 方法中Runnable 接口被調(diào)用唆姐。

本文轉(zhuǎn)載于:https://mp.weixin.qq.com/s/8LnmMAc1NnClqHAZGYwQtg

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市廓八,隨后出現(xiàn)的幾起案子奉芦,更是在濱河造成了極大的恐慌赵抢,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,946評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件声功,死亡現(xiàn)場(chǎng)離奇詭異烦却,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)先巴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)其爵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人伸蚯,你說(shuō)我怎么就攤上這事摩渺。” “怎么了剂邮?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,716評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵摇幻,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我抗斤,道長(zhǎng)囚企,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,222評(píng)論 1 300
  • 正文 為了忘掉前任瑞眼,我火速辦了婚禮,結(jié)果婚禮上棵逊,老公的妹妹穿的比我還像新娘伤疙。我一直安慰自己,他們只是感情好辆影,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,223評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布徒像。 她就那樣靜靜地躺著,像睡著了一般蛙讥。 火紅的嫁衣襯著肌膚如雪锯蛀。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,807評(píng)論 1 314
  • 那天次慢,我揣著相機(jī)與錄音旁涤,去河邊找鬼。 笑死迫像,一個(gè)胖子當(dāng)著我的面吹牛劈愚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闻妓,決...
    沈念sama閱讀 41,235評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼菌羽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了由缆?” 一聲冷哼從身側(cè)響起注祖,我...
    開(kāi)封第一講書(shū)人閱讀 40,189評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤猾蒂,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后是晨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體肚菠,經(jīng)...
    沈念sama閱讀 46,712評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,775評(píng)論 3 343
  • 正文 我和宋清朗相戀三年署鸡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了案糙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,926評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡靴庆,死狀恐怖时捌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情炉抒,我是刑警寧澤奢讨,帶...
    沈念sama閱讀 36,580評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站焰薄,受9級(jí)特大地震影響拿诸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜塞茅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,259評(píng)論 3 336
  • 文/蒙蒙 一亩码、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧野瘦,春花似錦描沟、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,750評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至惰许,卻和暖如春席覆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背汹买。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,867評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工佩伤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人卦睹。 一個(gè)月前我還...
    沈念sama閱讀 49,368評(píng)論 3 379
  • 正文 我出身青樓畦戒,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親结序。 傳聞我的和親對(duì)象是個(gè)殘疾皇子障斋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,930評(píng)論 2 361

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