簡單理解Android事件分發(fā)機(jī)制(下)——走進(jìn)源碼解析原理

本篇文章將從源碼的角度解析事件分發(fā)機(jī)制的詳細(xì)內(nèi)容聋丝。關(guān)于上篇文章的那些情況迥異的分發(fā)處理過程,是如何在源碼中實(shí)現(xiàn)的工碾?本篇文章將逐一揭曉弱睦。

一、分發(fā)機(jī)制中三個(gè)方法的關(guān)系

上篇文章關(guān)于dispatchTouchEvent()方法渊额,onInterceptTouchEvent()方法和onTouchEvent ()方法的流程進(jìn)行了梳理况木。那么在源碼實(shí)現(xiàn)中,三者之間的關(guān)系具體是什么樣的旬迹?用一段偽代碼來介紹火惊。

/ 點(diǎn)擊事件產(chǎn)生后,會(huì)直接調(diào)用dispatchTouchEvent()方法
public boolean dispatchTouchEvent(MotionEvent ev) {
   //代表是否消耗事件
    boolean consume = false;
    if (onInterceptTouchEvent(ev)) {
    //如果onInterceptTouchEvent()返回true則代表當(dāng)前View攔截了點(diǎn)擊事件
    //則該點(diǎn)擊事件則會(huì)交給當(dāng)前View進(jìn)行處理
    //即調(diào)用onTouchEvent ()方法去處理點(diǎn)擊事件
      consume = onTouchEvent (ev) ;
    } else {
      //如果onInterceptTouchEvent()返回false則代表當(dāng)前View不攔截點(diǎn)擊事件
      //則該點(diǎn)擊事件則會(huì)繼續(xù)傳遞給它的子元素
      //子元素的dispatchTouchEvent()就會(huì)被調(diào)用奔垦,重復(fù)上述過程
      //直到點(diǎn)擊事件被最終處理為止
      consume = child.dispatchTouchEvent (ev) ;
    }
    return consume;
   }

上述偽代碼清楚地描述了屹耐,事件分發(fā)從Activity->ViewGroup->View過程中,三大方法之間的調(diào)用關(guān)系椿猎。

二惶岭、Activity中的分發(fā)機(jī)制

上篇文章,我們介紹到犯眠,分發(fā)機(jī)制是從Activity開始的俗他,當(dāng)觸摸屏幕時(shí),Activity先感受到阔逼,并調(diào)用dispatchTouchEvent()方法進(jìn)行分發(fā)兆衅。下面就來具體了解這一方法的內(nèi)容。

public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        //第一次按下操作時(shí),用戶希望能與設(shè)備進(jìn)行交互羡亩,可通過實(shí)現(xiàn)該方法
        onUserInteraction();
    }

    //獲取當(dāng)前Activity的頂層窗口是PhoneWindow,執(zhí)行其superDispatchTouchEvent()方法
    if (getWindow().superDispatchTouchEvent(ev)) {
        return true;
    }
    //當(dāng)沒有任何view處理時(shí)摩疑,交由activity的onTouchEvent處理
    return onTouchEvent(ev);
}

可以看到,當(dāng)Activity向下分發(fā)事件畏铆,最終沒有任何控件進(jìn)行處理后雷袋,將會(huì)交給Activity的onTouchEvent()方法處理。
繼續(xù)看superDispatchTouchEvent()方法

public boolean superDispatchTouchEvent(KeyEvent event) {
    return mDecor.superDispatcTouchEvent(event);
}

PhoneWindow的最頂View是DecorView辞居,再交由DecorView處理楷怒。而DecorView的父類的父類是ViewGroup,接著調(diào)用 ViewGroup.dispatchTouchEvent()方法。

所以Activity中的分發(fā)機(jī)制簡述為:若不重寫該方法瓦灶,則調(diào)用根ViewGroup的dispatchTouchEvent()方法鸠删,進(jìn)行分發(fā),如果事件沒有任何控件進(jìn)行處理贼陶,則最后返回給Activity的onTouchEvent()方法進(jìn)行處理刃泡。若重寫該方法,不論返回值是false/true碉怔,都不會(huì)向下進(jìn)行事件分發(fā)烘贴,也就是事件停止分發(fā),已經(jīng)在Activity中消費(fèi)了撮胧。

三桨踪、ViewGroup中的分發(fā)機(jī)制

從Acivity中向下分發(fā),就到達(dá)了ViewGroup中的dispatchTouchEvent()方法芹啥,下面來具體看看這個(gè)方法馒闷。
該方法比較復(fù)雜,篇幅有限叁征,就截取幾個(gè)重要的邏輯片段進(jìn)行介紹纳账,來解析整個(gè)分發(fā)流程。

         // 發(fā)生ACTION_DOWN事件或者已經(jīng)發(fā)生過ACTION_DOWN,并且將mFirstTouchTarget賦值捺疼,才進(jìn)入此區(qū)域疏虫,主要功能是攔截器
        final boolean intercepted;
        if (actionMasked == MotionEvent.ACTION_DOWN|| mFirstTouchTarget != null) {
            //disallowIntercept:是否禁用事件攔截的功能(默認(rèn)是false),即不禁用
            //可以在子View通過調(diào)用requestDisallowInterceptTouchEvent方法對(duì)這個(gè)值進(jìn)行修改,不讓該View攔截事件
            final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
            //默認(rèn)情況下會(huì)進(jìn)入該方法
            if (!disallowIntercept) {
                //調(diào)用攔截方法
                intercepted = onInterceptTouchEvent(ev); 
                ev.setAction(action);
            } else {
                intercepted = false;
            }
        } else {
            // 當(dāng)沒有觸摸targets啤呼,且不是down事件時(shí)卧秘,開始持續(xù)攔截觸摸。
            intercepted = true;
        }

這一段的內(nèi)容主要是為判斷是否攔截官扣。如果當(dāng)前事件的MotionEvent.ACTION_DOWN翅敌,則進(jìn)入判斷,調(diào)用ViewGroup onInterceptTouchEvent()方法的值惕蹄,判斷是否攔截蚯涮。如果mFirstTouchTarget != null治专,即已經(jīng)發(fā)生過MotionEvent.ACTION_DOWN,并且該事件已經(jīng)有ViewGroup的子View進(jìn)行處理了遭顶,那么也進(jìn)入判斷张峰,調(diào)用ViewGroup onInterceptTouchEvent()方法的值,判斷是否攔截棒旗。如果不是以上兩種情況喘批,即已經(jīng)是MOVE或UP事件了,并且之間的事件沒有對(duì)象進(jìn)行處理铣揉,則設(shè)置成true饶深,開始攔截接下來的所有事件。這也就解釋了如果子View的onTouchEvent()方法返回false逛拱,那么接下來的一些列事件都不會(huì)交給他處理敌厘。其實(shí)這并不是onTouchEvent()方法傲嬌,而是onInterceptTouchEvent()方法沒給他機(jī)會(huì)橘券,直接攔截了额湘,不給子View機(jī)會(huì)卿吐。如果VieGroup的onInterceptTouchEvent()第一次執(zhí)行為true旁舰,則mFirstTouchTarget = null,則也會(huì)使得接下來不會(huì)調(diào)用onInterceptTouchEvent()嗡官,直接將攔截設(shè)置為true箭窜。

當(dāng)ViewGroup不攔截事件的時(shí)候,事件會(huì)向下分發(fā)交由它的子View或ViewGroup進(jìn)行處理衍腥。

                    /* 從最底層的父視圖開始遍歷磺樱,
                    ** 找尋newTouchTarget,即上面的mFirstTouchTarget
                    ** 如果已經(jīng)存在找尋newTouchTarget婆咸,說明正在接收觸摸事件竹捉,則跳出循環(huán)。
                    */
                    for (int i = childrenCount - 1; i >= 0; i--) {
                        final int childIndex = customOrder
                                ? getChildDrawingOrder(childrenCount, i) : i;
                        final View child = (preorderedList == null)
                                ? children[childIndex] : preorderedList.get(childIndex);

                        // 如果當(dāng)前視圖無法獲取用戶焦點(diǎn)尚骄,則跳過本次循環(huán)
                        if (childWithAccessibilityFocus != null) {
                            if (childWithAccessibilityFocus != child) {
                                continue;
                            }
                            childWithAccessibilityFocus = null;
                            i = childrenCount - 1;
                        }
                        //如果view不可見块差,或者觸摸的坐標(biāo)點(diǎn)不在view的范圍內(nèi),則跳過本次循環(huán)
                        if (!canViewReceivePointerEvents(child)
                                || !isTransformedTouchPointInView(x, y, child, null)) {
                            ev.setTargetAccessibilityFocus(false);
                            continue;
                        }

                        newTouchTarget = getTouchTarget(child);
                        // 已經(jīng)開始接收觸摸事件,并退出整個(gè)循環(huán)倔丈。
                        if (newTouchTarget != null) {
                            newTouchTarget.pointerIdBits |= idBitsToAssign;
                            break;
                        }

                        //重置取消或抬起標(biāo)志位
                        //如果觸摸位置在child的區(qū)域內(nèi)憨闰,則把事件分發(fā)給子View或ViewGroup
                        if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                            // 獲取TouchDown的時(shí)間點(diǎn)
                            mLastTouchDownTime = ev.getDownTime();
                            // 獲取TouchDown的Index
                            if (preorderedList != null) {
                                for (int j = 0; j < childrenCount; j++) {
                                    if (children[childIndex] == mChildren[j]) {
                                        mLastTouchDownIndex = j;
                                        break;
                                    }
                                }
                            } else {
                                mLastTouchDownIndex = childIndex;
                            }

                            //獲取TouchDown的x,y坐標(biāo)
                            mLastTouchDownX = ev.getX();
                            mLastTouchDownY = ev.getY();
                            //添加TouchTarget,則mFirstTouchTarget != null。
                            newTouchTarget = addTouchTarget(child, idBitsToAssign);
                            //表示以及分發(fā)給NewTouchTarget
                            alreadyDispatchedToNewTouchTarget = true;
                            break;
                        }

dispatchTransformedTouchEvent()方法實(shí)際就是調(diào)用子元素的dispatchTouchEvent()方法需五。
其中dispatchTransformedTouchEvent()方法的重要邏輯如下:

 if (child == null) {
                handled = super.dispatchTouchEvent(event);
            } else {
                handled = child.dispatchTouchEvent(event);
            }

由于其中傳遞的child不為空鹉动,所以就會(huì)調(diào)用子元素的dispatchTouchEvent()。
如果子元素的dispatchTouchEvent()方法返回true宏邮,那么mFirstTouchTarget就會(huì)被賦值泽示,同時(shí)跳出for循環(huán)缸血。

//添加TouchTarget,則mFirstTouchTarget != null。
newTouchTarget = addTouchTarget(child, idBitsToAssign);
 //表示以及分發(fā)給NewTouchTarget
 alreadyDispatchedToNewTouchTarget = true;

其中在addTouchTarget(child, idBitsToAssign);內(nèi)部完成mFirstTouchTarget被賦值边琉。
如果mFirstTouchTarget為空属百,將會(huì)讓ViewGroup默認(rèn)攔截所有操作。
如果遍歷所有子View或ViewGroup变姨,都沒有消費(fèi)事件族扰。ViewGroup會(huì)自己處理事件。

所以ViewGroup中的分發(fā)機(jī)制簡述為:若子View或ViewGroup不處理MotionEvent.ACTION_DOWN事件定欧,那么接下來的一些列事件都交由ViewGroup處理渔呵。若ViewGroup的onInterceptTouchEvent()執(zhí)行為true,則接下來的所有事件都默認(rèn)由該ViewGroup執(zhí)行砍鸠。若子View或ViewGroup處理MotionEvent.ACTION_DOWN事件扩氢,則接下來的事件處理交給誰要看onInterceptTouchEvent()的返回值,如果返回true爷辱,則第一個(gè)MOVE事件录豺,會(huì)變成CANCEL事件,繼續(xù)交由原來的子View或ViewGroup處理饭弓,接下來的一些列事件都交由ViewGroup執(zhí)行双饥。如果返回false,則繼續(xù)交給原來的子View或ViewGroup處理弟断。

四咏花、View中的分發(fā)機(jī)制

View中的分發(fā)機(jī)制就比較簡單了。上面ViewGroup中已經(jīng)開始調(diào)用View.dispatchTouchEvent()方法,下面來具體看一下阀趴。

public boolean dispatchTouchEvent(MotionEvent event) {
    ...
    
    final int actionMasked = event.getActionMasked();
    if (actionMasked == MotionEvent.ACTION_DOWN) {
        //在Down事件之前昏翰,如果存在滾動(dòng)操作則停止。不存在則不進(jìn)行操作
        stopNestedScroll();
    }
    if (onFilterTouchEventForSecurity(event)) {
        ListenerInfo li = mListenerInfo;
        //第一個(gè)條件默認(rèn)為true
        //第二個(gè)條件mOnTouchListener 不為空
       //第三個(gè)條件該條件是判斷當(dāng)前點(diǎn)擊的控件是否enable 
       //第四個(gè)條件onTouch返回值是true
        if (li != null && li.mOnTouchListener != null
                && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnTouchListener.onTouch(this, event)) {
            result = true; //滿足上述四個(gè)條件刘急,已經(jīng)消費(fèi)事件棚菊,則返回True
        }
        //如果OnTouch()返回false,或者沒滿足其他條件叔汁,沒有消費(fèi)Touch事件則調(diào)用OnTouchEvent()
        if (!result && onTouchEvent(event)) { 
            result = true; //onTouchEvent(event)返回true统求,已經(jīng)消費(fèi)事件,則返回True
        }
    }

    if (!result && mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
    }

    // 處理取消或抬起操作
    if (actionMasked == MotionEvent.ACTION_UP ||
            actionMasked == MotionEvent.ACTION_CANCEL ||
            (actionMasked == MotionEvent.ACTION_DOWN && !result)) {
        stopNestedScroll();
    }

    return result;
}

針對(duì)上述四個(gè)條件的判斷攻柠,很多View默認(rèn)是(mViewFlags & ENABLED_MASK) == ENABLED,通過設(shè)置OnTouchListener中的onTouch返回true球订,那么onTouchEvent()方法就不會(huì)調(diào)用,表明OnTouchListener的優(yōu)先級(jí)高于onTouchEvent瑰钮。

//手動(dòng)調(diào)用設(shè)置
button.setOnTouchListener(new OnTouchListener() {  

  @Override  
  public boolean onTouch(View v, MotionEvent event) {  

      return false;  
  }  
});

如果OnTouchListener中的onTouch返回false冒滩,那么會(huì)調(diào)用onTouchEvent()方法。

public boolean onTouchEvent(MotionEvent event) {
    final float x = event.getX();
    final float y = event.getY();
    final int viewFlags = mViewFlags;

    // 當(dāng)View狀態(tài)為DISABLED浪谴,如果可點(diǎn)擊或可長按开睡,則返回True因苹,即消費(fèi)事件
    if ((viewFlags & ENABLED_MASK) == DISABLED) {
        if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
            setPressed(false);
        }
        return (((viewFlags & CLICKABLE) == CLICKABLE ||
                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));
    }

    if (mTouchDelegate != null) {
        if (mTouchDelegate.onTouchEvent(event)) {
            return true;
        }
    }

    //當(dāng)View狀態(tài)為ENABLED,如果可點(diǎn)擊或可長按篇恒,則返回True扶檐,即消費(fèi)事件;
    //與前面的的結(jié)合,可得出結(jié)論:只要view是可點(diǎn)擊或可長按胁艰,則消費(fèi)該事件.
    if (((viewFlags & CLICKABLE) == CLICKABLE ||
            (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
                if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
                    boolean focusTaken = false;
                    if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
                        focusTaken = requestFocus();
                    }

                    if (prepressed) {
                        setPressed(true, x, y);
                   }

                    if (!mHasPerformedLongPress) {
                        //這是Tap操作款筑,移除長按回調(diào)方法
                        removeLongPressCallback();

                        if (!focusTaken) {
                            if (mPerformClick == null) {
                                mPerformClick = new PerformClick();
                            }
                            //調(diào)用View.OnClickListener
                            if (!post(mPerformClick)) {
                                performClick();
                            }
                        }
                    }

                    if (mUnsetPressedState == null) {
                        mUnsetPressedState = new UnsetPressedState();
                    }

                    if (prepressed) {
                        postDelayed(mUnsetPressedState,
                                ViewConfiguration.getPressedStateDuration());
                    } else if (!post(mUnsetPressedState)) {
                        mUnsetPressedState.run();
                    }

                    removeTapCallback();
                }
                break;

            case MotionEvent.ACTION_DOWN:
                mHasPerformedLongPress = false;

                if (performButtonActionOnTouchDown(event)) {
                    break;
                }

                //獲取是否處于可滾動(dòng)的視圖內(nèi)
                boolean isInScrollingContainer = isInScrollingContainer();

                if (isInScrollingContainer) {
                    mPrivateFlags |= PFLAG_PREPRESSED;
                    if (mPendingCheckForTap == null) {
                        mPendingCheckForTap = new CheckForTap();
                    }
                    mPendingCheckForTap.x = event.getX();
                    mPendingCheckForTap.y = event.getY();
                    //當(dāng)處于可滾動(dòng)視圖內(nèi),則延遲TAP_TIMEOUT腾么,再反饋按壓狀態(tài)奈梳,用來判斷用戶是否想要滾動(dòng)。默認(rèn)延時(shí)為100ms
                    postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                } else {
                    //當(dāng)不再滾動(dòng)視圖內(nèi)解虱,則立刻反饋按壓狀態(tài)
                    setPressed(true, x, y);
                    checkForLongClick(0); //檢測是否是長按
                }
                break;

            case MotionEvent.ACTION_CANCEL:
                setPressed(false);
                removeTapCallback();
                removeLongPressCallback();
                break;

            case MotionEvent.ACTION_MOVE:
                drawableHotspotChanged(x, y);

                if (!pointInView(x, y, mTouchSlop)) {
                    removeTapCallback();
                    if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
                        removeLongPressCallback();
                        setPressed(false);
                    }
                }
                break;
        }

        return true;
    }
    return false;
}

只要View的CLICKABLE和LONG_CLICKABLE有一個(gè)為true攘须,那么它就會(huì)消耗這個(gè)事件。
如果View設(shè)置了OnClickLisenter殴泰,那么performClick方法內(nèi)部就會(huì)調(diào)用onClick方法于宙。

public boolean performClick() {  
    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);  

    if (mOnClickListener != null) {  
        playSoundEffect(SoundEffectConstants.CLICK);  
        mOnClickListener.onClick(this);  
        return true;  
    }  
    return false;  
}

則表明onTouch()優(yōu)先級(jí)高于onTouchEvent(),并高于onClick()悍汛。
所以View中的分發(fā)機(jī)制簡述為:默認(rèn)情況下捞魁,如果View的CLICKABLE和LONG_CLICKABLE有一個(gè)為true(默認(rèn)LONG_CLICKABLE為false,一般可以點(diǎn)擊的View中CLICKABLE為true员凝。)署驻,則就會(huì)消費(fèi)該事件奋献,如果都為false健霹,則不會(huì)消費(fèi)該事件,dispatchTouchEvent()方法返回false瓶蚂,交由父控件的循環(huán)下一個(gè)子View進(jìn)行同樣操作糖埋。如果重寫onTouchEvent()方法,返回false,dispatchTouchEvent()方法返回false窃这,交由父控件的循環(huán)下一個(gè)子View進(jìn)行同樣操作瞳别。如果重寫onTouchEvent()方法,返回true杭攻,則消費(fèi)該事件祟敛。

以上就是源碼解析事件分發(fā)的內(nèi)容。
參考文章:
Android事件分發(fā)機(jī)制完全解析兆解,帶你從源碼的角度徹底理解(上)
Android事件分發(fā)機(jī)制完全解析馆铁,帶你從源碼的角度徹底理解(下)
Android事件分發(fā)機(jī)制

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市锅睛,隨后出現(xiàn)的幾起案子埠巨,更是在濱河造成了極大的恐慌历谍,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辣垒,死亡現(xiàn)場離奇詭異望侈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)勋桶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門脱衙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人例驹,你說我怎么就攤上這事岂丘。” “怎么了眠饮?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵奥帘,是天一觀的道長。 經(jīng)常有香客問我仪召,道長寨蹋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任扔茅,我火速辦了婚禮已旧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘召娜。我一直安慰自己运褪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布玖瘸。 她就那樣靜靜地躺著秸讹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪雅倒。 梳的紋絲不亂的頭發(fā)上璃诀,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音蔑匣,去河邊找鬼劣欢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛裁良,可吹牛的內(nèi)容都是我干的凿将。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼价脾,長吁一口氣:“原來是場噩夢啊……” “哼牧抵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起彼棍,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤灭忠,失蹤者是張志新(化名)和其女友劉穎膳算,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弛作,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涕蜂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了映琳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片机隙。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖萨西,靈堂內(nèi)的尸體忽然破棺而出有鹿,到底是詐尸還是另有隱情,我是刑警寧澤谎脯,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布葱跋,位于F島的核電站,受9級(jí)特大地震影響源梭,放射性物質(zhì)發(fā)生泄漏娱俺。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一废麻、第九天 我趴在偏房一處隱蔽的房頂上張望荠卷。 院中可真熱鬧,春花似錦烛愧、人聲如沸油宜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽慎冤。三九已至,卻和暖如春社牲,著一層夾襖步出監(jiān)牢的瞬間粪薛,已是汗流浹背悴了。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來泰國打工搏恤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人湃交。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓熟空,卻偏偏與公主長得像,于是被迫代替她去往敵國和親搞莺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子息罗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

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