第三章 View事件體系(2)之事件分發(fā)

本文為Android開發(fā)藝術(shù)探索的筆記,僅供學(xué)習(xí)

1 事件的分發(fā)機(jī)制

上面幾節(jié)介紹了View的滑動體系,現(xiàn)在我們要來將一個View 非常核心的一個知識點,事件的分發(fā)機(jī)制枢析,不論是初學(xué)者還是中級開發(fā)者都要面對的一個問題就是滑動沖突,為了去解決該問題致燥,我們需要更多的去了解一些基本的分發(fā)機(jī)制,從而去解決這個滑動沖突排截。

1.1點擊事件的傳遞

其實事件的分發(fā)是要是對motionEvent進(jìn)行分發(fā)嫌蚤,大家都是知道里面包括了三個MotionAction辐益,那么系統(tǒng)需要對該事件進(jìn)行分發(fā),分發(fā)就需要去認(rèn)識一下三個函數(shù)


分發(fā)事件的機(jī)制大致就是脱吱,對于一個跟ViewGroup來說智政,當(dāng)有點擊事件產(chǎn)生的時候,會調(diào)用dispathtouchevent方法箱蝠,如果這個Viewgroup的onIntercept返回true就表示要對該事件進(jìn)行攔截续捂,那么就會調(diào)用Viewgroup的OntouchEvent去處理這個事件,若不攔截則把該事件傳給子節(jié)點的View也不執(zhí)行Viewgroup的OntouchEvent方法宦搬,該view也一樣會調(diào)用disdispathtoucheventath方法牙瓢,也會對該事件是否進(jìn)行攔截進(jìn)行處理,若不攔截就不執(zhí)行OntouchEvent间校,就這樣遞歸的傳遞矾克,若最后一個view也不處理,那么改使事件回傳給父容器憔足。

當(dāng)View設(shè)置ontouchListener的時候胁附,就會回調(diào)一個ontouch方法,若返回true則ontouchevent就不執(zhí)行滓彰,返回false這反之控妻,這里可以看到ontouchListener的優(yōu)先級大于ontouchevent, 我們再來看ontouchevent中揭绑,如果我們設(shè)置了OnClickListener弓候,那么onclick才會被回掉,所以ontouchevent的優(yōu)先級大于OnClickListener洗做,總結(jié)一下優(yōu)先級ontouchListener>ontouchevent>OnClickListener弓叛。

為了便于理解ontouchevent和OnClickListener的優(yōu)先級我們來看看ontouchevent的源碼
下面這一段代碼是在ViewGroup的ACTION_UP事件里

switch (action) {
                case MotionEvent.ACTION_UP:
                    boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
                            ......
                            if (!focusTaken) {
                                // Use a Runnable and post this rather than calling
                                // performClick directly. This lets other visual state
                                // of the view update before click actions start.
                                if (mPerformClick == null) {
                                    mPerformClick = new PerformClick();
                                }
                                if (!post(mPerformClick)) {
                                    performClick();
                                }
                            }
                        }

performClick方法實現(xiàn)了onClick的回調(diào)

  public boolean performClick() {
        final boolean result;
        final ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnClickListener != null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            li.mOnClickListener.onClick(this);
            result = true;
        } else {
            result = false;
        }

        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
        return result;
    }

故可以看出ontouchevent的優(yōu)先級OnClickListener,至于ontouchListener的優(yōu)先級在后面的源碼中會講解诚纸。
我們先來總結(jié)一下分發(fā)事件機(jī)制

  1. 同一個時間序列是指從手指接觸屏幕的那一刻起撰筷,到手指離開屏幕的那一刻結(jié)束,在這個過程中所產(chǎn)生的一系列事情畦徘,這個事件序列以down事件開始毕籽,中間含有數(shù)量不定的move事件,最終以up事件結(jié)束井辆。
  2. 正常情況下关筒,一個事件序列只能被一個View攔截且消耗。
  3. 因為一旦一個元素攔截了某次事件杯缺,那么同一個時間序列內(nèi)的所有時間都會直接交給它處理蒸播,因此同一個時間序列中的時間不能分別有兩個View同時處理,但是通過特殊手段可以做到,比如一個View將本該自己處理的事件通過onTouchEvent強(qiáng)行傳遞給其他View處理袍榆。
  4. 某個View一旦決定攔截胀屿,那個這一個事件序列都只能由它來處理(如果時間序列能過傳遞給它的話),并且它的onInterceptTouchEvent不會再被調(diào)用包雀。這條也很好理解宿崭,就是說當(dāng)一個View決定攔截一個事件后,那么系統(tǒng)會把同一個事件序列內(nèi)的其他方法都直接交給它來處理才写,因此就不會再調(diào)用這個View的onInterceptTouchEvent去詢問它是否要攔截了葡兑。
  5. 某一個View一旦開始處理事件,如果它不消耗ACTION_DOWN事件(onTouchEvent返回了false)赞草,那么同一事件序列中的其它事件都不會再交給他來處理讹堤,并且事件將重新交由它的夫元素去處理,即父元素的onTouchEvent會被調(diào)用房资。
  6. 如果View不消耗ACTION_DOWN以外的其他事件蜕劝,那么這個點擊事件會消失,此時父元素的onTouchEvent并不會被調(diào)用轰异,并且當(dāng)前View可以持續(xù)收到后續(xù)的事件岖沛,最終這些消失的點擊事件會傳遞給Activity處理。
  7. ViewGroup默認(rèn)不攔截任何事件搭独。Android源碼中ViewGroup的onInterceptTouchEvent方法默認(rèn)返回false婴削。
  8. View沒有onInterceptTouchEvent方法,一旦有點擊事件傳遞給它牙肝,那么它的onTouchEvent方法就會被調(diào)用唉俗。
  9. View的enable屬性不影響onTouchEvent的默認(rèn)返回值。哪怕一個View是disable狀態(tài)的配椭,只要它的clickable或者longClickable有一個為true虫溜,那么它的onTouchEvent就返回true。
  10. onClick會發(fā)生的提前是當(dāng)前View是可點擊的股缸,并且它收到了down和up的事件衡楞。
  11. 事件傳遞過程是由外向內(nèi)的,即事件總是先傳遞給父元素敦姻,然后在有父元素分發(fā)給予View瘾境,通過requestDisallowInterecptTouchEvent方法可以在子元素中干預(yù)父元素的事件分發(fā)過程,但是ACTION_DOWN事件除外镰惦。

1.2事件分發(fā)的源碼解析

我們先來說說最頂端的分發(fā)迷守,首先Activity-->Window-->View(具體實現(xiàn)后面幾個章節(jié)會解釋)
對頂級View的點擊事件的分發(fā)大致解釋一下
關(guān)于點擊事件如何在View中進(jìn)行分發(fā),當(dāng)點擊事件達(dá)到頂層View(一般是一個ViewGroup)以后旺入,會調(diào)用ViewGroup的dispatchTouchEvent方法兑凿,然后得邏輯是這樣的:如果頂層ViewGroup攔截事件即onInterceptTouchEvent返回true凯力,則事件由ViewGroup處理,這時如果ViewGroup的mOnTouchListener被設(shè)置礼华,則onTouch會被調(diào)用沮协,否則onTouchEvent會被調(diào)用。也就是說如果都提供了的話卓嫂,onTouch會屏蔽掉onTouchEvent。在onTouchEvent中聘殖,如果設(shè)置了mOnClickListener晨雳,則onClick會被調(diào)用。也就是OnTouchListener奸腺,onTouchEvent餐禁,onClick三者優(yōu)先級的關(guān)系。如果頂層ViewGroup不攔截事件突照,則事件會傳遞給它所在的點擊事件鏈上的子View帮非,這是子View的dispatchTouchEvent會被調(diào)用。如果子View需要處理該事件就進(jìn)行攔截讹蘑,則會調(diào)用onTouchEvent末盔,如果不處理就將事件傳給下一個View,以此循環(huán)座慰。

接下來我們來看看viewgroup的diapatchTouchEvent的部分源碼
final boolean intercepted;
*if (actionMasked == MotionEvent.ACTION_DOWN
        || mFirstTouchTarget != null)* {
    final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
    *if (!disallowIntercept)* {
        intercepted = onInterceptTouchEvent(ev);
        ev.setAction(action); // restore action in case it was changed
    } else {
        intercepted = false;
    }
} else {
    // There are no touch targets and this action is not an initial down
    // so this view group continues to intercept touches.
    intercepted = true;
}

我們可以看到判斷事件是否被攔截一共有兩個判斷就是**包裹的部分

第一個判斷是有兩個參數(shù)陨舱,第一個是ACTION_DOWN和mFirstTouchTarget,前者就是一個點擊事件版仔,后者就是當(dāng)ViewGroup的子View去處理了該事件游盲,那么該View對象就會賦值給mFirstTouchTarget。

第二個判斷就是就是子View是否有FLAG_DISALLOW_INTERCEPT標(biāo)記位蛮粮,該標(biāo)記位一般是子View通過requstDisallowInterceptTouchEvent去設(shè)置的益缎,目的就是為了讓ViewGroup無法攔截除了ACTION_DOWN以外的其他事件,為什么這樣說呢然想?因為ACTION_DOWN事件會重置FLAG_DISALLOW_INTERCEPT莺奔,也就是說FLAG_DISALLOW_INTERCEPT標(biāo)記位對ACTION_DOWN無效。下面代碼說明為什么無效又沾。

// Handle an initial down.
if (actionMasked == MotionEvent.ACTION_DOWN) {
    // Throw away all previous state when starting a new touch gesture.
    // The framework may have dropped the up or cancel event for the previous gesture
    // due to an app switch, ANR, or some other state change.
    cancelAndClearTouchTargets(ev);//從英文可以看出 取消和清除標(biāo)記位
    resetTouchState();//會先清除弊仪,再讓其賦予該標(biāo)記位,且不攔截除了ACTION_DOWN的事件
}
private void resetTouchState() {
    clearTouchTargets();
    resetCancelNextUpFlag(this);
    mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
    mNestedScrollAxes = SCROLL_AXIS_NONE;
}

可以看出FLAG_DISALLOW_INTERCEPT的標(biāo)記位了就讓ViewGroup攔截住了
上述中我們可以總結(jié)兩點
1.onInterceptTouchEvent方法并不是每次都會執(zhí)行杖刷,如果想要提前處理好所有的點擊事件励饵,要選擇dispatchTouchEvent,因為只有該方法每次都會被調(diào)用滑燃。
2.FLAG_DISALLOW_INTERCEPT標(biāo)記位給我們提供了一個思路役听,在處理一些滑動沖突的時候,我們是不是可以利用這個標(biāo)記位?


接下來看看ViewGroup不攔截的時候的分發(fā)給子View的處理
final int childrenCount = mChildrenCount;
if (newTouchTarget == null && childrenCount != 0) {
    final float x = ev.getX(actionIndex);//獲取點擊事件的坐標(biāo)
    final float y = ev.getY(actionIndex);
    // Find a child that can receive the event. 找到一個可以接收事件的孩子典予。
    // Scan children from front to back.掃描孩子從前面到后面
    final ArrayList<View> preorderedList = buildTouchDispatchChildList();
    final boolean customOrder = preorderedList == null
            && isChildrenDrawingOrderEnabled();
    final View[] children = mChildren;
    for (int i = childrenCount - 1; i >= 0; i--) {
        final int childIndex = getAndVerifyPreorderedIndex(
                childrenCount, i, customOrder);
        final View child = getAndVerifyPreorderedView(
                preorderedList, children, childIndex);

        // If there is a view that has accessibility focus we want it  
        // to get the event first and if not handled we will perform a  
        // normal dispatch. We may do a double iteration but this is
        // safer given the timeframe.  如果有一個視圖甜滨,它具有可訪問性的焦點,我們希望它首先得到事件瘤袖,如果沒有處理衣摩,我們將執(zhí)行一個正常的調(diào)度。我                 們可以做一個雙迭代捂敌,但這是更安全的時間表艾扮。
   *  if (childWithAccessibilityFocus != null) {//這是判斷事件是否具有焦點
            if (childWithAccessibilityFocus != child) {//判斷這焦點是否是對應(yīng)的view
                continue;
            }
            childWithAccessibilityFocus = null;
            i = childrenCount - 1;
        }
        if (!canViewReceivePointerEvents(child)//該方法就是判斷點擊事件的坐標(biāo)是否落在View里面
                || !isTransformedTouchPointInView(x, y, child, null)) {
            ev.setTargetAccessibilityFocus(false);
            continue;
        } *
        newTouchTarget = getTouchTarget(child);
        if (newTouchTarget != null) {
            // Child is already receiving touch within its bounds.
            // Give it the new pointer in addition to the ones it is handling.孩子已經(jīng)在它的范圍內(nèi)接受觸摸,除了它正在處理的外占婉,給它新指針.泡嘴。
            newTouchTarget.pointerIdBits |= idBitsToAssign;
            break;
        }
        resetCancelNextUpFlag(child);
        if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
            // Child wants to receive touch within its bounds.
            mLastTouchDownTime = ev.getDownTime();
            if (preorderedList != null) {
                // childIndex points into presorted list, find original index
                for (int j = 0; j < childrenCount; j++) {
                    if (children[childIndex] == mChildren[j]) {
                        mLastTouchDownIndex = j;
                        break;
                    }
                }
            } else {
                mLastTouchDownIndex = childIndex;
            }
            mLastTouchDownX = ev.getX();
            mLastTouchDownY = ev.getY();
            newTouchTarget = addTouchTarget(child, idBitsToAssign);
            alreadyDispatchedToNewTouchTarget = true;
            break;
        }

*包裹的部分的兩個判斷
當(dāng)有子View的時候,決定時間是否分發(fā)到子View有兩個要素逆济,
第一個就是判斷子View是否有焦點酌予,因為有焦點的話是不能獲取到點擊事件,所以我們要保證子View能獲取到焦點
第二就是判斷點擊事件的坐標(biāo)是否落在子View上

其中dispatchTransformedTouchEvent方法就是調(diào)用了子View的dispatchTouchEvent奖慌,從而完成了吧點擊事件分發(fā)到子View

private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
        View child, int desiredPointerIdBits) {
    final boolean handled;
    // Canceling motions is a special case.  We don't need to perform any transformations
    // or filtering.  The important part is the action, not the contents.
    final int oldAction = event.getAction();
    if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
        event.setAction(MotionEvent.ACTION_CANCEL);
        if (child == null) {
            handled = super.dispatchTouchEvent(event);
        } else {
            handled = child.dispatchTouchEvent(event);
        }
        event.setAction(oldAction);
        return handled;
    }

我們再來看看這段代碼

newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;

這段代碼完成了mFirstTouchEvent的賦值抛虫,并且跳出該循環(huán),前面也已經(jīng)說了mFirstTouchEvent所指向的是處理事件的View简僧,如果為空ViewGroup就是攔截 我們來看看源碼

if (mFirstTouchTarget == null) {
    // No touch targets so treat this as an ordinary view.
    handled = dispatchTransformedTouchEvent(ev, canceled, null,
            TouchTarget.ALL_POINTER_IDS);
} 

mFirstTouchEvent的賦值主要是通過addTouchTarget這個方法莱褒,那么我來看看addTouchTarget的源碼

private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
    final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
    target.next = mFirstTouchTarget;
    mFirstTouchTarget = target;
    return target;
}

講完了ViewGroup,我們來看看View對點擊事件的處理涎劈,我們先來看看View的diapatchTouchEvent

public boolean dispatchTouchEvent(MotionEvent event) {
    ...
    boolean result = false;
    ...
    if (onFilterTouchEventForSecurity(event)) {
        if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
            result = true;
        }
        //noinspection SimplifiableIfStatement
        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnTouchListener != null
                && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnTouchListener.onTouch(this, event)) {
            result = true;
        }
        if (!result && onTouchEvent(event)) {
            result = true;
        }
    }
    ...
    return result;
}

因為View不是ViewGroup所以就不需要再分發(fā)事件了广凸,我們可以看到View先要去判斷是否設(shè)置了onTouchListener,若返回true這不去調(diào)用onTouchEvent蛛枚,這里就不說優(yōu)先級了之前說過谅海。

我們再來看看onTouchEvent的實現(xiàn)過程

if ((viewFlags & ENABLED_MASK) == DISABLED) {
    if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
        setPressed(false);
    }
    // A disabled view that is clickable still consumes the touch
    // events, it just doesn't respond to them.
    return (((viewFlags & CLICKABLE) == CLICKABLE
            || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
            || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE);
}

(enable表示View是否可用) 通過enable,我們可以看到View處于不可用狀態(tài)蹦浦,但是不影響事件是消耗和onTouchEvent的返回扭吁。

if (mTouchDelegate != null) {//TouchEdlegate類的作用是增大View的點擊范圍
    if (mTouchDelegate.onTouchEvent(event)) {
        return true;
    }
}

下面看onTouchEvent對事件的處理

if (((viewFlags & CLICKABLE) == CLICKABLE ||
        (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
        (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
    switch (action) {
        case MotionEvent.ACTION_UP:
            boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
            if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
                // take focus if we don't have it already and we should in
                // touch mode.
                boolean focusTaken = false;
                if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
                    focusTaken = requestFocus();
                }

                if (prepressed) {
                    // The button is being released before we actually
                    // showed it as pressed.  Make it show the pressed
                    // state now (before scheduling the click) to ensure
                    // the user sees it.
                    setPressed(true, x, y);
               }

                if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
                    // This is a tap, so remove the longpress check
                    removeLongPressCallback();

                    // Only perform take click actions if we were in the pressed state
                    if (!focusTaken) {
                        // Use a Runnable and post this rather than calling
                        // performClick directly. This lets other visual state
                        // of the view update before click actions start.
                        if (mPerformClick == null) {
                            mPerformClick = new PerformClick();
                        }
                        if (!post(mPerformClick)) {
                            performClick();
                        }
                    }
                }

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

                if (prepressed) {
                    postDelayed(mUnsetPressedState,
                            ViewConfiguration.getPressedStateDuration());
                } else if (!post(mUnsetPressedState)) {
                    // If the post failed, unpress right now
                    mUnsetPressedState.run();
                }

                removeTapCallback();
            }
            mIgnoreNextUpEvent = false;
            break;

        case MotionEvent.ACTION_DOWN:
            ...
            break;

        case MotionEvent.ACTION_CANCEL:
         ...
            break;

        case MotionEvent.ACTION_MOVE:
             ...
            break;
    }

不管是CLICKABLE LONG_CLICKABLE CONTEXT_CLICKABLE 只要有一個為true 就可以消耗事件,在ACTION_UP事件里的performClick方法盲镶,在View設(shè)置了onclickListener的話會回掉該方法里的onClick方法

public boolean performClick() {
    final boolean result;
    final ListenerInfo li = mListenerInfo;
    if (li != null && li.mOnClickListener != null) {
        playSoundEffect(SoundEffectConstants.CLICK);
        li.mOnClickListener.onClick(this);
        result = true;
    } else {
        result = false;
    }

    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
    return result;
}

所以想要回掉onclick侥袜,必須要設(shè)置CLICKABLE LONG_CLICKABLE CONTEXT_CLICKABLE 中的其中一個為true就可以了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市溉贿,隨后出現(xiàn)的幾起案子枫吧,更是在濱河造成了極大的恐慌,老刑警劉巖宇色,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件九杂,死亡現(xiàn)場離奇詭異颁湖,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)例隆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進(jìn)店門甥捺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人镀层,你說我怎么就攤上這事镰禾。” “怎么了唱逢?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵羡微,是天一觀的道長。 經(jīng)常有香客問我惶我,道長,這世上最難降的妖魔是什么博投? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任绸贡,我火速辦了婚禮,結(jié)果婚禮上毅哗,老公的妹妹穿的比我還像新娘听怕。我一直安慰自己,他們只是感情好虑绵,可當(dāng)我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布尿瞭。 她就那樣靜靜地躺著,像睡著了一般翅睛。 火紅的嫁衣襯著肌膚如雪声搁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天捕发,我揣著相機(jī)與錄音疏旨,去河邊找鬼。 笑死扎酷,一個胖子當(dāng)著我的面吹牛檐涝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播法挨,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼谁榜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了凡纳?” 一聲冷哼從身側(cè)響起窃植,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎荐糜,沒想到半個月后撕瞧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體陵叽,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年丛版,在試婚紗的時候發(fā)現(xiàn)自己被綠了巩掺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡页畦,死狀恐怖胖替,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情豫缨,我是刑警寧澤独令,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站好芭,受9級特大地震影響燃箭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜舍败,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一招狸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧邻薯,春花似錦裙戏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至灵嫌,卻和暖如春壹罚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背寿羞。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工渔嚷, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人稠曼。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓形病,卻偏偏與公主長得像,于是被迫代替她去往敵國和親霞幅。 傳聞我的和親對象是個殘疾皇子漠吻,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,922評論 2 361

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