Android TV 焦點(diǎn)原理源碼解析

  • 前言

相信很多剛接觸AndroidTV開發(fā)的開發(fā)者涧黄,都會(huì)被各種焦點(diǎn)問(wèn)題給折磨的不行。不管是學(xué)技術(shù)還是學(xué)習(xí)其他知識(shí)赋荆,都要學(xué)習(xí)和理解其中原理笋妥,碰到問(wèn)題我們才能得心應(yīng)手。下面就來(lái)探一探Android的焦點(diǎn)分發(fā)的過(guò)程窄潭。

  • Android焦點(diǎn)分發(fā)春宣,攔截過(guò)程的實(shí)現(xiàn)

Android焦點(diǎn)事件的分發(fā)是從ViewRootImpl的processKeyEvent開始的,源碼如下:

        private int processKeyEvent(QueuedInputEvent q) {
            final KeyEvent event = (KeyEvent)q.mEvent;

            // Deliver the key to the view hierarchy.
            if (mView.dispatchKeyEvent(event)) {
                return FINISH_HANDLED;
            }

            if (shouldDropInputEvent(q)) {
                return FINISH_NOT_HANDLED;
            }

            // If the Control modifier is held, try to interpret the key as a shortcut.
            if (event.getAction() == KeyEvent.ACTION_DOWN
                    && event.isCtrlPressed()
                    && event.getRepeatCount() == 0
                    && !KeyEvent.isModifierKey(event.getKeyCode())) {
                if (mView.dispatchKeyShortcutEvent(event)) {
                    return FINISH_HANDLED;
                }
                if (shouldDropInputEvent(q)) {
                    return FINISH_NOT_HANDLED;
                }
            }

            // Apply the fallback event policy.
            if (mFallbackEventHandler.dispatchKeyEvent(event)) {
                return FINISH_HANDLED;
            }
            if (shouldDropInputEvent(q)) {
                return FINISH_NOT_HANDLED;
            }

            // Handle automatic focus changes.
            if (event.getAction() == KeyEvent.ACTION_DOWN) {
                int direction = 0;
                switch (event.getKeyCode()) {
                    case KeyEvent.KEYCODE_DPAD_LEFT:
                        if (event.hasNoModifiers()) {
                            direction = View.FOCUS_LEFT;
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_RIGHT:
                        if (event.hasNoModifiers()) {
                            direction = View.FOCUS_RIGHT;
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_UP:
                        if (event.hasNoModifiers()) {
                            direction = View.FOCUS_UP;
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_DOWN:
                        if (event.hasNoModifiers()) {
                            direction = View.FOCUS_DOWN;
                        }
                        break;
                    case KeyEvent.KEYCODE_TAB:
                        if (event.hasNoModifiers()) {
                            direction = View.FOCUS_FORWARD;
                        } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
                            direction = View.FOCUS_BACKWARD;
                        }
                        break;
                }
                if (direction != 0) {
                    View focused = mView.findFocus();
                    if (focused != null) {
                        View v = focused.focusSearch(direction);
                        if (v != null && v != focused) {
                            // do the math the get the interesting rect
                            // of previous focused into the coord system of
                            // newly focused view
                            focused.getFocusedRect(mTempRect);
                            if (mView instanceof ViewGroup) {
                                ((ViewGroup) mView).offsetDescendantRectToMyCoords(
                                        focused, mTempRect);
                                ((ViewGroup) mView).offsetRectIntoDescendantCoords(
                                        v, mTempRect);
                            }
                            if (v.requestFocus(direction, mTempRect)) {
                                playSoundEffect(SoundEffectConstants
                                        .getContantForFocusDirection(direction));
                                return FINISH_HANDLED;
                            }
                        }

                        // Give the focused view a last chance to handle the dpad key.
                        if (mView.dispatchUnhandledMove(focused, direction)) {
                            return FINISH_HANDLED;
                        }
                    } else {
                        // find the best view to give focus to in this non-touch-mode with no-focus
                        View v = focusSearch(null, direction);
                        if (v != null && v.requestFocus(direction)) {
                            return FINISH_HANDLED;
                        }
                    }
                }
            }
            return FORWARD;
        }

源碼比較長(zhǎng)嫉你,下面我就慢慢來(lái)講解一下具體的每一個(gè)細(xì)節(jié)月帝。

  • (1) 首先由dispatchKeyEvent進(jìn)行焦點(diǎn)的分發(fā),如果dispatchKeyEvent方法返回true幽污,那么下面的焦點(diǎn)查找步驟就不會(huì)繼續(xù)了嚷辅。

dispatchKeyEvent方法返回true代表焦點(diǎn)事件被消費(fèi)了。

  // Deliver the key to the view hierarchy.
            if (mView.dispatchKeyEvent(event)) {
                return FINISH_HANDLED;
            }
  • 首先會(huì)執(zhí)行mView的dispatchKeyEvent方法距误,估計(jì)大家會(huì)好奇這個(gè)mView是個(gè)什么鬼簸搞?其實(shí)它就是Activity的頂層容器DecorView,它是一FrameLayout准潭。所以這里的dispatchKeyEvent方法應(yīng)該執(zhí)行的是ViewGroup的dispatchKeyEvent()方法趁俊,而不是View的dispatchKeyEvent方法。

ViewGroup的dispatchKeyEvent()方法的源碼如下:

 @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onKeyEvent(event, 1);
        }

        if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
                == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
            if (super.dispatchKeyEvent(event)) {
                return true;
            }
        } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
                == PFLAG_HAS_BOUNDS) {
            if (mFocused.dispatchKeyEvent(event)) {
                return true;
            }
        }

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
        }
        return false;
    }

(2)ViewGroup的dispatchKeyEvent執(zhí)行流程

  • 首先ViewGroup會(huì)一層一層往上執(zhí)行父類的dispatchKeyEvent方法刑然,如果返回true那么父類的dispatchKeyEvent方法就會(huì)返回true寺擂,也就代表父類消費(fèi)了該焦點(diǎn)事件,那么焦點(diǎn)事件自然就不會(huì)往下進(jìn)行分發(fā)泼掠。
  • 然后ViewGroup會(huì)判斷mFocused這個(gè)view是否為空怔软,如果為空就會(huì)return false,焦點(diǎn)繼續(xù)往下傳遞武鲁;如果不為空爽雄,那就會(huì)return mFocused的dispatchKeyEvent方法返回的結(jié)果蝠检。這個(gè)mFocused是什么呢沐鼠?其實(shí)
    是ViewGroup中當(dāng)前獲取焦點(diǎn)的子View,這個(gè)可以從requestChildFocus方法中得到答案叹谁。requestChildFocus()的源碼如下:
 @Override
    public void requestChildFocus(View child, View focused) {
        if (DBG) {
            System.out.println(this + " requestChildFocus()");
        }
        if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
            return;
        }

        // Unfocus us, if necessary
        super.unFocus(focused);

        // We had a previous notion of who had focus. Clear it.
        if (mFocused != child) {
            if (mFocused != null) {
                mFocused.unFocus(focused);
            }

            mFocused = child;
        }
        if (mParent != null) {
            mParent.requestChildFocus(this, focused);
        }
    }

(3)下面再來(lái)瞧瞧view的dispatchKeyEvent方法的具體的執(zhí)行過(guò)程

  public boolean dispatchKeyEvent(KeyEvent event) {
        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onKeyEvent(event, 0);
        }

        // Give any attached key listener a first crack at the event.
        //noinspection SimplifiableIfStatement
        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
            return true;
        }

        if (event.dispatch(this, mAttachInfo != null
                ? mAttachInfo.mKeyDispatchState : null, this)) {
            return true;
        }

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }
        return false;
    }

驚奇的發(fā)現(xiàn)執(zhí)行了onKeyListener中的onKey方法饲梭,如果onKey方法返回true,那么dispatchKeyEvent方法也會(huì)返回true

可以得出結(jié)論:如果想要修改ViewGroup焦點(diǎn)事件的分發(fā)焰檩,可以這么干:

  • 重寫view的dispatchKeyEvent方法
  • 給某個(gè)子view設(shè)置onKeyListener監(jiān)聽

注意:實(shí)際開發(fā)中憔涉,理論上所有焦點(diǎn)問(wèn)題都可以通過(guò)給dispatchKeyEvent方法增加監(jiān)聽來(lái)來(lái)攔截來(lái)控制。

  • **回到ViewRootImpl中析苫,焦點(diǎn)沒(méi)有被dispatchKeyEvent攔截的情況下的處理過(guò)程 **

(1)dispatchKeyEvent方法返回false后兜叨,先得到按鍵的方向direction值穿扳,這個(gè)值是一個(gè)int類型參數(shù)。這個(gè)direction值是后面來(lái)進(jìn)行焦點(diǎn)查找的国旷。

  // Handle automatic focus changes.
            if (event.getAction() == KeyEvent.ACTION_DOWN) {
                int direction = 0;
                switch (event.getKeyCode()) {
                    case KeyEvent.KEYCODE_DPAD_LEFT:
                        if (event.hasNoModifiers()) {
                            direction = View.FOCUS_LEFT;
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_RIGHT:
                        if (event.hasNoModifiers()) {
                            direction = View.FOCUS_RIGHT;
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_UP:
                        if (event.hasNoModifiers()) {
                            direction = View.FOCUS_UP;
                        }
                        break;
                    case KeyEvent.KEYCODE_DPAD_DOWN:
                        if (event.hasNoModifiers()) {
                            direction = View.FOCUS_DOWN;
                        }
                        break;
                    case KeyEvent.KEYCODE_TAB:
                        if (event.hasNoModifiers()) {
                            direction = View.FOCUS_FORWARD;
                        } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
                            direction = View.FOCUS_BACKWARD;
                        }
                        break;
                }

(2)接著會(huì)調(diào)用DecorView的findFocus()方法一層一層往下查找已經(jīng)獲取焦點(diǎn)的子View矛物。
ViewGroup的findFocus方法如下:

 @Override
    public View findFocus() {
        if (DBG) {
            System.out.println("Find focus in " + this + ": flags="
                    + isFocused() + ", child=" + mFocused);
        }

        if (isFocused()) {
            return this;
        }

        if (mFocused != null) {
            return mFocused.findFocus();
        }
        return null;
    }

View的findFocus方法

 public View findFocus() {
        return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null;
    }

說(shuō)明:判斷view是否獲取焦點(diǎn)的isFocused()方法, (mPrivateFlags & PFLAG_FOCUSED) != 0 和view 的isFocused()方法是一致的跪但。

  @ViewDebug.ExportedProperty(category = "focus")
    public boolean isFocused() {
        return (mPrivateFlags & PFLAG_FOCUSED) != 0;
    }

其中isFocused()方法的作用是判斷view是否已經(jīng)獲取焦點(diǎn)履羞,如果viewGroup已經(jīng)獲取到了焦點(diǎn),那么返回本身即可屡久,否則通過(guò)mFocused的findFocus()方法來(lái)找焦點(diǎn)忆首。mFocused其實(shí)就是ViewGroup中獲取焦點(diǎn)的子view,如果mView不是ViewGourp的話被环,findFocus其實(shí)就是判斷本身是否已經(jīng)獲取焦點(diǎn)糙及,如果已經(jīng)獲取焦點(diǎn)了,返回本身蛤售。

(3)回到processKeyEvent方法中丁鹉,如果findFocus方法返回的mFocused不為空,說(shuō)明找到了當(dāng)前獲取焦點(diǎn)的view(mFocused)悴能,接著focusSearch會(huì)把direction(遙控器按鍵按下的方向)作為參數(shù)揣钦,找到特定方向下一個(gè)將要獲取焦點(diǎn)的view,最后如果該view不為空漠酿,那么就讓該view獲取焦點(diǎn)冯凹。

 if (direction != 0) {
                    View focused = mView.findFocus();
                    if (focused != null) {
                        View v = focused.focusSearch(direction);
                        if (v != null && v != focused) {
                            // do the math the get the interesting rect
                            // of previous focused into the coord system of
                            // newly focused view
                            focused.getFocusedRect(mTempRect);
                            if (mView instanceof ViewGroup) {
                                ((ViewGroup) mView).offsetDescendantRectToMyCoords(
                                        focused, mTempRect);
                                ((ViewGroup) mView).offsetRectIntoDescendantCoords(
                                        v, mTempRect);
                            }
                            if (v.requestFocus(direction, mTempRect)) {
                                playSoundEffect(SoundEffectConstants
                                        .getContantForFocusDirection(direction));
                                return FINISH_HANDLED;
                            }
                        }

                        // Give the focused view a last chance to handle the dpad key.
                        if (mView.dispatchUnhandledMove(focused, direction)) {
                            return FINISH_HANDLED;
                        }
                    } else {
                        // find the best view to give focus to in this non-touch-mode with no-focus
                        View v = focusSearch(null, direction);
                        if (v != null && v.requestFocus(direction)) {
                            return FINISH_HANDLED;
                        }
                    }
                }

(4)focusSearch方法的具體實(shí)現(xiàn)。

focusSearch方法的源碼如下:

  @Override
    public View focusSearch(View focused, int direction) {
        if (isRootNamespace()) {
            // root namespace means we should consider ourselves the top of the
            // tree for focus searching; otherwise we could be focus searching
            // into other tabs.  see LocalActivityManager and TabHost for more info
            return FocusFinder.getInstance().findNextFocus(this, focused, direction);
        } else if (mParent != null) {
            return mParent.focusSearch(focused, direction);
        }
        return null;
    }

可以看出focusSearch其實(shí)是一層一層地網(wǎng)上調(diào)用父View的focusSearch方法炒嘲,直到當(dāng)前view是根布局(isRootNamespace()方法)宇姚,通過(guò)注釋可以知道focusSearch最終會(huì)調(diào)用DecorView的focusSearch方法。而DecorView的focusSearch方法找到的焦點(diǎn)view是通過(guò)FocusFinder來(lái)找到的夫凸。

  @Override
    public View focusSearch(View focused, int direction) {
        if (isRootNamespace()) {
            // root namespace means we should consider ourselves the top of the
            // tree for focus searching; otherwise we could be focus searching
            // into other tabs.  see LocalActivityManager and TabHost for more info
            return FocusFinder.getInstance().findNextFocus(this, focused, direction);
        } else if (mParent != null) {
            return mParent.focusSearch(focused, direction);
        }
        return null;
    }

(5)FocusFinder是什么浑劳?

它其實(shí)是一個(gè)實(shí)現(xiàn) 根據(jù)給定的按鍵方向,通過(guò)當(dāng)前的獲取焦點(diǎn)的View夭拌,查找下一個(gè)獲取焦點(diǎn)的view這樣算法的類魔熏。焦點(diǎn)沒(méi)有被攔截的情況下,Android框架焦點(diǎn)的查找最終都是通過(guò)FocusFinder類來(lái)實(shí)現(xiàn)的鸽扁。

(6)FocusFinder是如何通過(guò)findNextFocus方法尋找焦點(diǎn)的蒜绽。

下面就來(lái)看看FocusFinder類是如何通過(guò)findNextFocus來(lái)找焦點(diǎn)的。一層一層往下看桶现,后面會(huì)執(zhí)行findNextUserSpecifiedFocus()方法躲雅,這個(gè)方法會(huì)執(zhí)行focused(即當(dāng)前獲取焦點(diǎn)的View)的findUserSetNextFocus方法,如果該方法返回的View不為空骡和,且isFocusable = true && isInTouchMode() = true的話相赁,F(xiàn)ocusFinder找到的焦點(diǎn)就是findNextUserSpecifiedFocus()返回的View相寇。

   private View findNextUserSpecifiedFocus(ViewGroup root, View focused, int direction) {
        // check for user specified next focus
        View userSetNextFocus = focused.findUserSetNextFocus(root, direction);
        if (userSetNextFocus != null && userSetNextFocus.isFocusable()
                && (!userSetNextFocus.isInTouchMode()
                        || userSetNextFocus.isFocusableInTouchMode())) {
            return userSetNextFocus;
        }
        return null;
    }

(7)findNextFocus會(huì)優(yōu)先根據(jù)XML里設(shè)置的下一個(gè)將獲取焦點(diǎn)的View ID值來(lái)尋找將要獲取焦點(diǎn)的View。

看看View的findUserSetNextFocus方法內(nèi)部都干了些什么钮科,OMG不就是通過(guò)我們xml布局里設(shè)置的nextFocusLeft裆赵,nextFocusRight的viewId來(lái)找焦點(diǎn)嗎,如果按下Left鍵跺嗽,那么便會(huì)通過(guò)nextFocusLeft值里的View Id值去找下一個(gè)獲取焦點(diǎn)的View战授。

 View findUserSetNextFocus(View root, @FocusDirection int direction) {
        switch (direction) {
            case FOCUS_LEFT:
                if (mNextFocusLeftId == View.NO_ID) return null;
                return findViewInsideOutShouldExist(root, mNextFocusLeftId);
            case FOCUS_RIGHT:
                if (mNextFocusRightId == View.NO_ID) return null;
                return findViewInsideOutShouldExist(root, mNextFocusRightId);
            case FOCUS_UP:
                if (mNextFocusUpId == View.NO_ID) return null;
                return findViewInsideOutShouldExist(root, mNextFocusUpId);
            case FOCUS_DOWN:
                if (mNextFocusDownId == View.NO_ID) return null;
                return findViewInsideOutShouldExist(root, mNextFocusDownId);
            case FOCUS_FORWARD:
                if (mNextFocusForwardId == View.NO_ID) return null;
                return findViewInsideOutShouldExist(root, mNextFocusForwardId);
            case FOCUS_BACKWARD: {
                if (mID == View.NO_ID) return null;
                final int id = mID;
                return root.findViewByPredicateInsideOut(this, new Predicate<View>() {
                    @Override
                    public boolean apply(View t) {
                        return t.mNextFocusForwardId == id;
                    }
                });
            }
        }
        return null;
    }

可以得出以下結(jié)論:

1. 如果一個(gè)View在XML布局中設(shè)置了focusable = true && isInTouchMode = true,那么這個(gè)View會(huì)優(yōu)先獲取焦點(diǎn)桨嫁。

2. 通過(guò)設(shè)置nextFocusLeft植兰,nextFocusRight,nextFocusUp璃吧,nextFocusDown值可以控制View的下一個(gè)焦點(diǎn)楣导。

Android焦點(diǎn)的原理實(shí)現(xiàn)就這些⌒蟀ぃ總結(jié)一下:

  • **首先DecorView會(huì)調(diào)用dispatchKey一層一層進(jìn)行焦點(diǎn)的分發(fā)筒繁,如果dispatchKeyEvent方法返回true的話,那么焦點(diǎn)就不會(huì)往下分發(fā)了巴元。 **

  • 中途可以給某個(gè)子View設(shè)置OnKeyListener進(jìn)行焦點(diǎn)的攔截毡咏。

  • **如果焦點(diǎn)沒(méi)有被攔截的話,那么焦點(diǎn)就會(huì)交給系統(tǒng)來(lái)處理 **

  • Android底層先會(huì)記錄按鍵的方向逮刨,后面DecorView會(huì)一層一層往下調(diào)用findFocus方法找到當(dāng)前獲取焦點(diǎn)的View

  • 后面系統(tǒng)又會(huì)根據(jù)按鍵的方向呕缭,執(zhí)行focusSearch方法來(lái)尋找下一個(gè)將要獲取焦點(diǎn)的View

  • focusSearch內(nèi)部其實(shí)是通過(guò)FocusFinder來(lái)查找焦點(diǎn)的。FocusFinder會(huì)優(yōu)先通過(guò)View在XML布局設(shè)置的下一個(gè)焦點(diǎn)的ID來(lái)查找焦點(diǎn)修己。

  • 最終如果找到將要獲取焦點(diǎn)的View恢总,就讓其requestFocus。

為了方便同志們學(xué)習(xí)睬愤,我這做了張導(dǎo)圖片仿,方便大家理解~


Android焦點(diǎn)事件分發(fā)機(jī)制.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市尤辱,隨后出現(xiàn)的幾起案子砂豌,更是在濱河造成了極大的恐慌,老刑警劉巖啥刻,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奸鸯,死亡現(xiàn)場(chǎng)離奇詭異咪笑,居然都是意外死亡可帽,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門窗怒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)映跟,“玉大人蓄拣,你說(shuō)我怎么就攤上這事∨叮” “怎么了球恤?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)荸镊。 經(jīng)常有香客問(wèn)我咽斧,道長(zhǎng),這世上最難降的妖魔是什么躬存? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任张惹,我火速辦了婚禮,結(jié)果婚禮上岭洲,老公的妹妹穿的比我還像新娘宛逗。我一直安慰自己,他們只是感情好盾剩,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布雷激。 她就那樣靜靜地躺著,像睡著了一般告私。 火紅的嫁衣襯著肌膚如雪屎暇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天驻粟,我揣著相機(jī)與錄音恭垦,去河邊找鬼。 笑死格嗅,一個(gè)胖子當(dāng)著我的面吹牛番挺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播屯掖,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼玄柏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了贴铜?” 一聲冷哼從身側(cè)響起粪摘,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绍坝,沒(méi)想到半個(gè)月后徘意,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡轩褐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年椎咧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡勤讽,死狀恐怖蟋座,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情脚牍,我是刑警寧澤向臀,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站诸狭,受9級(jí)特大地震影響券膀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜驯遇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一三娩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧妹懒,春花似錦雀监、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至匾竿,卻和暖如春瓦宜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背岭妖。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工临庇, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人昵慌。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓假夺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親斋攀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子已卷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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