Android事件分發(fā)機(jī)制前篇——事件如何傳遞到Activity中

網(wǎng)上關(guān)于Android事件分發(fā)機(jī)制的資料有許多,看過很多次怠益,但是每次過一段時(shí)間就會(huì)忘記仪搔,感覺還是自己研究的不夠深入,這一次蜻牢,決定自己根據(jù)源碼烤咧,來好好梳理一遍Android事件分發(fā)機(jī)制的知識,本篇文章講的主要是一個(gè)觸摸事件抢呆,如何傳入到Activity中煮嫌。

事件的入口

首先是有一個(gè)疑問,我們討論事件分發(fā)抱虐,那么究竟事件的來源是哪里呢昌阿?我們知道ActivitydispatchTouchEvent(MotionEvent ev)是會(huì)接受到事件的,所以我們在該方法中調(diào)用Thread.dumpStack()來查看調(diào)用棧。

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Thread.dumpStack();
        return super.dispatchTouchEvent(ev);
    }

運(yùn)行程序懦冰,輸出結(jié)果為:

at java.lang.Thread.dumpStack(Thread.java:490)
at com.dpal.javademo.MainActivity.dispatchTouchEvent(MainActivity.java:30)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:68)
at com.android.internal.policy.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2364)
at android.view.View.dispatchPointerEvent(View.java:9539)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4281)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4144)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3683)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3736)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3702)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3828)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3710)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3885)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3683)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3736)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3702)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3710)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3683)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5973)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5947)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5908)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6079)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:195)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:323)
at android.os.Looper.loop(Looper.java:141)
at android.app.ActivityThread.main(ActivityThread.java:5653)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:746)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:636)

具體分析

at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6079)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:195)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:323)

我們知道Android的消息機(jī)制是Handler機(jī)制灶轰,通過將消息封裝到Message中,再發(fā)送到消息所在Handler所在MessageQueue中刷钢,并且Looper不斷調(diào)用MessageQueuenext()方法進(jìn)行消息的處理框往。所以根據(jù)上面的調(diào)用信息,當(dāng)我們觸摸屏幕時(shí)闯捎,nativePollOnce()將會(huì)收到消息椰弊,并且將事件發(fā)送給InputEventReceiverdispatchInputEvent()方法

直接從名字我們應(yīng)該能看出它的作用,輸入事件的接受者瓤鼻。我們再來看看官方對InputEventReceiver的描述

/**
 * Provides a low-level mechanism for an application to receive input events.
 * 提供應(yīng)用程序接收輸入事件的低級機(jī)制秉版。
 * @hide
 */
public abstract class InputEventReceiver {
  
   /**
     * Creates an input event receiver bound to the specified input channel.
     *  創(chuàng)建綁定到指定輸入通道的輸入事件接收器。
     * @param inputChannel The input channel.
     * @param looper The looper to use when invoking callbacks.
     */
    public InputEventReceiver(InputChannel inputChannel, Looper looper) {
        if (inputChannel == null) {
            throw new IllegalArgumentException("inputChannel must not be null");
        }
        if (looper == null) {
            throw new IllegalArgumentException("looper must not be null");
        }

        mInputChannel = inputChannel;
        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
                inputChannel, mMessageQueue);

        mCloseGuard.open("dispose");
    }

    /**
     * Called when an input event is received.
     * 當(dāng)接收到輸入事件時(shí)調(diào)用茬祷。
     *
     * @param event The input event that was received.
     */
    public void onInputEvent(InputEvent event) {
        finishInputEvent(event, false);
    }

    // Called from native code.
    @SuppressWarnings("unused")
    private void dispatchInputEvent(int seq, InputEvent event) {
        mSeqMap.put(event.getSequenceNumber(), seq);
        onInputEvent(event);
    }

    private void dispose(boolean finalized) {
        if (mCloseGuard != null) {
            if (finalized) {
                mCloseGuard.warnIfOpen();
            }
            mCloseGuard.close();
        }

        if (mReceiverPtr != 0) {
            nativeDispose(mReceiverPtr);
            mReceiverPtr = 0;
        }
        mInputChannel = null;
        mMessageQueue = null;
    }
}

我省略了一些不關(guān)鍵的代碼清焕,果然,InputEventReceover提供了應(yīng)用程序接受輸入事件的低級機(jī)制祭犯,在它的構(gòu)造器中秸妥,我們看到了一個(gè)nativeInit()方法的調(diào)用,這里系統(tǒng) native 層就會(huì)將這個(gè)InputEventReceiver實(shí)例記錄下來沃粗,每當(dāng)有事件到達(dá)時(shí)就會(huì)通過inputChannel管道派發(fā)到這個(gè)實(shí)例上粥惧,當(dāng)然還有注銷的方法:dipose()。在InputEventReceiver中最盅,我們看到dispatchInputEvent()方法注釋著從native層代碼調(diào)用突雪,也就是nativePollOnce()內(nèi)部會(huì)調(diào)用這個(gè)方法。

大家注意這里的InputEventReceiver是一個(gè)抽象類涡贱,再根據(jù)棧中的信息咏删,事件將會(huì)傳到ViewRootImpl$WindowInputEventReceiver.onInputEvent()中,說明nativePollOnce()其實(shí)調(diào)用的是InputEventReceiver的子類WindoInputEventReceiverdispatchInputEvent()方法问词,然后再調(diào)用onInputEvent()方法督函。

WindowInputEventReceiverViewRootimpl的一個(gè)內(nèi)部類,我們來看一下他的源碼:

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {

    ···

    final class WindowInputEventReceiver extends InputEventReceiver {
        public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
        }

        @Override
        public void onInputEvent(InputEvent event) {
            enqueueInputEvent(event, this, 0, true);
        }

        @Override
        public void onBatchedInputEventPending() {
            if (mUnbufferedInputDispatch) {
                super.onBatchedInputEventPending();
            } else {
                scheduleConsumeBatchedInput();
            }
        }

        @Override
        public void dispose() {
            unscheduleConsumeBatchedInput();
            super.dispose();
        }
    }

    void enqueueInputEvent(InputEvent event,
            InputEventReceiver receiver, int flags, boolean processImmediately) {
        adjustInputEventForCompatibility(event);
        //將event事件激挪,receiver辰狡,flags包裝成一個(gè)QueuedInputEvent
        //QueuedInputEvent表示一個(gè)在隊(duì)列中等待處理的輸入事件,這個(gè)類有個(gè)next屬性可以指向下一個(gè)事件
        QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
        //獲得等待隊(duì)列的最后一個(gè)輸入事件(Pending的意思是等待的灌灾,Tail的意思是尾部)
        QueuedInputEvent last = mPendingInputEventTail;
        //下面的意思就是將事件加入到隊(duì)列中
        if (last == null) {
            //如果沒有最后一個(gè)搓译,就說明隊(duì)列是空的,那么第一個(gè)是該事件悲柱,最后一個(gè)也是該事件
            mPendingInputEventHead = q;
            mPendingInputEventTail = q;
        } else {
            //如果有最后一個(gè)锋喜,那么就將該事件設(shè)置成最后一個(gè)
            last.mNext = q;
            mPendingInputEventTail = q;
        }
        //隊(duì)列數(shù)量加1
        mPendingInputEventCount += 1;
        //事件跟蹤機(jī)制。。嘿般。不需要管
        Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
                mPendingInputEventCount);
        //如果事件需要立即處理段标,則執(zhí)行doProcessInputEvents(),
        //WindowInputEventReceiver中enqueueInputEvent(event, this, 0, true);傳入的是true
        if (processImmediately) {
            doProcessInputEvents();
        } else {
            scheduleProcessInputEvents();
        }
    }
    ···
}

省略了一些不關(guān)鍵的代碼炉奴,我們看到事件通過WindowInputEventReceiveronInputEvent()方法傳遞到了ViewRootImplenqueueInputEvent()中逼庞。在enqueueInputEvent()中,我已經(jīng)注釋了每一步的作用瞻赶,事件將會(huì)傳遞到doProcessInputEvents()方法中赛糟,我們再來看這個(gè)方法的源碼:

    void doProcessInputEvents() {
        // 處理隊(duì)列中所有的輸入事件
        while (mPendingInputEventHead != null) {
            //下面這段代碼是取出事件隊(duì)列中的第一個(gè),若有第二個(gè)砸逊,將其置為第一個(gè)
            QueuedInputEvent q = mPendingInputEventHead;
            mPendingInputEventHead = q.mNext;
            if (mPendingInputEventHead == null) {
                mPendingInputEventTail = null;
            }
            q.mNext = null;
            //隊(duì)列數(shù)量減1
            mPendingInputEventCount -= 1;
            //跟蹤事件璧南,不需要管
            Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
                    mPendingInputEventCount);
            
            //下面的代碼是獲得當(dāng)前事件的發(fā)生時(shí)間,以及此事件與上一個(gè)事件間隔間隔時(shí)間
            //通過Choreographer师逸,協(xié)調(diào)動(dòng)畫司倚、輸入和繪圖的時(shí)間
            long eventTime = q.mEvent.getEventTimeNano();
            long oldestEventTime = eventTime;
            if (q.mEvent instanceof MotionEvent) {
                MotionEvent me = (MotionEvent)q.mEvent;
                if (me.getHistorySize() > 0) {
                    oldestEventTime = me.getHistoricalEventTimeNano(0);
                }
            }
            mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
        
            deliverInputEvent(q);
        }

        // 處理完了所有的輸入事件,將處理事件等待標(biāo)記設(shè)為false
        if (mProcessInputEventsScheduled) {
            mProcessInputEventsScheduled = false;
            mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
        }
    }

Ok篓像,我們看到在doProcessInputEvents()方法中动知,輸入事件從一個(gè)一個(gè)從隊(duì)列中被取出,并傳入deliverInputEvent()方法中员辩,這一點(diǎn)完全和文章開頭的調(diào)用棧信息相同:

at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5973)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5947)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5908)

我們繼續(xù)說deliverInputEvent()方法盒粮,通過方法名,這個(gè)方法的作用應(yīng)該是傳遞輸入事件的吧奠滑?究竟是不是呢拆讯?我們繼續(xù)探究它的代碼:

    private void deliverInputEvent(QueuedInputEvent q) {
        //跟蹤機(jī)制,不用管
        Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
                q.mEvent.getSequenceNumber());
       //一致性驗(yàn)證养叛,不用管种呐,一致性驗(yàn)證就是比如說判斷ACTION_DOWN和ACTION_UP是否成對出現(xiàn)
        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
        }
        
        InputStage stage;
        if (q.shouldSendToSynthesizer()) {
            stage = mSyntheticInputStage;
        } else {
            stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
        }

        if (stage != null) {
            stage.deliver(q);
        } else {
            finishInputEvent(q);
        }
    }

在這個(gè)方法中,得到了一個(gè)InputStage對象弃甥。它是處理輸入事件的一個(gè)階段爽室,可以將事件完成或者轉(zhuǎn)送到下一個(gè)階段。InputStage分為多種淆攻,例如SyntheticInputStage阔墩、ViewPostImeInputStageNativePostImeInputStage等等瓶珊,Android在這里使用了設(shè)計(jì)模式中的責(zé)任鏈模式啸箫,多個(gè)InputStage連成一條鏈,并沿著這條鏈傳遞輸入事件伞芹,直到有一個(gè)InputStage處理了該輸入事件忘苛。觸摸事件就是由ViewPostImeInputStage處理蝉娜,這一點(diǎn)也可以通過文章一開始的調(diào)用棧輸出信息來確認(rèn),事件最終傳遞給了ViewPostImeInputStage中的onProcess()然后傳遞給processPointerEvent()方法:

我們先來看看ViewPostImeInputStage中的onProcess()方法:

        @Override
        protected int onProcess(QueuedInputEvent q) {
            if (q.mEvent instanceof KeyEvent) {
                //按鍵事件扎唾,比如回退鍵
                return processKeyEvent(q);
            } else {
                final int source = q.mEvent.getSource();
                if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
                    //普通的觸摸點(diǎn)事件
                    return processPointerEvent(q);
                } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
                    //軌跡球事件召川,我并不清楚軌跡球是啥玩意,應(yīng)該是下面那張軌跡球的圖片把胸遇?
                    return processTrackballEvent(q);
                } else {
                    //滾輪事件荧呐,比如外接藍(lán)牙鼠標(biāo)時(shí),可以觸發(fā)滾輪事件
                    return processGenericMotionEvent(q);
                }
            }
        }

在onProcess()方法中纸镊,根據(jù)判斷倍阐,分了四種情況處理輸入事件,具體的分類我在注釋中已經(jīng)給出逗威,本文我們只分析普通的觸摸事件收捣,也就是分析processPointerEvent()方法。

軌跡球

我們再來看processPointerEvent()方法的代碼:

        private int processPointerEvent(QueuedInputEvent q) {
            final MotionEvent event = (MotionEvent)q.mEvent;

            mAttachInfo.mUnbufferedDispatchRequested = false;
            mAttachInfo.mHandlingPointerEvent = true;
           //最關(guān)鍵的代碼b挚0瞻!尽纽!
            boolean handled = mView.dispatchPointerEvent(event);
            maybeUpdatePointerIcon(event);
            maybeUpdateTooltip(event);
            mAttachInfo.mHandlingPointerEvent = false;
            if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
                mUnbufferedInputDispatch = true;
                if (mConsumeBatchedInputScheduled) {
                    scheduleConsumeBatchedInputImmediately();
                }
            }
            return handled ? FINISH_HANDLED : FORWARD;
        }

來吧咐蚯,讓我們看到最關(guān)鍵的代碼,總算出現(xiàn)了View的蹤跡弄贿,其中的mView就是我們熟悉的DecorView了春锋。為什么mView就是DecorView呢?大家可以參考這篇文章Android View源碼解讀:淺談DecorView與ViewRootImpl差凹,我們進(jìn)入DecorView中的dispatchPointerEvent()方法中期奔。。危尿。咦呐萌?你是否真的在DecorView中找dispatchPointerEvent()方法了?哈哈哈谊娇,是不是找不到肺孤?當(dāng)然了!這個(gè)方法其實(shí)是在View類里面:

    public final boolean dispatchPointerEvent(MotionEvent event) {
        if (event.isTouchEvent()) {
            return dispatchTouchEvent(event);
        } else {
            return dispatchGenericMotionEvent(event);
        }
    }

好吧济欢,很簡單的幾行代碼赠堵,如果事件屬于觸摸事件,就調(diào)用dispatchTouchEvent(event)方法法褥,如果不是茫叭,則調(diào)用dispatchGenericMotionEvent(event)方法。讓我們繼續(xù)跟隨事件半等,進(jìn)入DecorView中的dispatchTouchEvent()揍愁,如下:

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        final Window.Callback cb = mWindow.getCallback();
        //mFeatureId :面板的特征ID呐萨,如果這是應(yīng)用程序的DecorView就為-1,在初始化時(shí)設(shè)置
        return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
                ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
    }

在這個(gè)方法中吗垮,mWindow就是與Activity關(guān)聯(lián)的PhoneWindow對象垛吗,由于DecorView是PhoneWindow創(chuàng)建的凹髓,并且通過setWindow()方法烁登,DecorView對象持有了PhoneWindow對象的引用。通過getCallback()方法蔚舀,就獲得了Window.Callback對象饵沧,Window.Callback包含了窗口的各種回調(diào)接口,Activity就實(shí)現(xiàn)了該接口赌躺。根據(jù)return后的判斷狼牺,當(dāng)調(diào)用cb.dispatchTouchEvent(ev)時(shí),其實(shí)調(diào)用的就是Activity中的dispatchTouchEvent()方法礼患。接下來就是從Activity出發(fā)是钥,進(jìn)一步分析事件分發(fā)機(jī)制了。

終于好了缅叠,讓我們來總結(jié)一下吧

  1. 首先悄泥,當(dāng)我們觸摸屏幕時(shí),通過Android消息機(jī)制肤粱,從Looper從MessageQueue中取出該事件弹囚,發(fā)送給WindowInputEventReceiver。
  2. WindowInputEventReceiver是ViewRootImpl的內(nèi)部類领曼,通過enqueueInputEvent方法鸥鹉,將輸入事件加入輸入事件隊(duì)列中,并進(jìn)行處理和轉(zhuǎn)發(fā)庶骄。
  3. ViewPostImeInputStage收到輸入事件毁渗,將事件傳遞給DecorView的dispatchPointerEvent()方法(是View的方法)
  4. dispatchPointerEvent()方法通過DecorView中的dispatchTouchEvent()方法,調(diào)用了Activity的dispatchTouchEvent()方法单刁。
    到此事件進(jìn)入Activity中Wr稹!;眉睢绎狭!進(jìn)入Activity后,事件又是如何被處理的呢褥傍?可以查看Android事件分發(fā)機(jī)制及源碼分析
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末儡嘶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子恍风,更是在濱河造成了極大的恐慌蹦狂,老刑警劉巖誓篱,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異凯楔,居然都是意外死亡窜骄,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門摆屯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來邻遏,“玉大人,你說我怎么就攤上這事虐骑∽佳椋” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵廷没,是天一觀的道長糊饱。 經(jīng)常有香客問我,道長颠黎,這世上最難降的妖魔是什么另锋? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮狭归,結(jié)果婚禮上夭坪,老公的妹妹穿的比我還像新娘。我一直安慰自己唉铜,他們只是感情好台舱,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著潭流,像睡著了一般竞惋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上灰嫉,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天拆宛,我揣著相機(jī)與錄音,去河邊找鬼讼撒。 笑死浑厚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的根盒。 我是一名探鬼主播钳幅,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼炎滞!你這毒婦竟也來了敢艰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤册赛,失蹤者是張志新(化名)和其女友劉穎钠导,沒想到半個(gè)月后震嫉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牡属,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年票堵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逮栅。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡悴势,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出证芭,到底是詐尸還是另有隱情瞳浦,我是刑警寧澤担映,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布废士,位于F島的核電站,受9級特大地震影響蝇完,放射性物質(zhì)發(fā)生泄漏官硝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一短蜕、第九天 我趴在偏房一處隱蔽的房頂上張望氢架。 院中可真熱鬧,春花似錦朋魔、人聲如沸岖研。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽孙援。三九已至,卻和暖如春扇雕,著一層夾襖步出監(jiān)牢的瞬間拓售,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工镶奉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留础淤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓哨苛,卻偏偏與公主長得像鸽凶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子建峭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345

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