FragmentManager checkStateLoss

一湃交、問(wèn)題

先來(lái)看兩個(gè)Crash Log:

1.

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
    at android.support.v4.app.ab.v(FragmentManager.java:1377)
    at android.support.v4.app.ab.a(FragmentManager.java:1395)
    at android.support.v4.app.h.a(BackStackRecord.java:637)
    at android.support.v4.app.h.b(BackStackRecord.java:616)
    at android.support.v4.app.DialogFragment.show(DialogFragment.java:139)
    at com.sankuai.common.views.ai.a(MaoyanDialogBuilder.java:184)
    at com.sankuai.movie.y.handleMessage(MovieMainActivity.java:750)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4424)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
    at dalvik.system.NativeStart.main(Native Method)

2.

java.lang.IllegalStateException: Can not perform this action inside of onLoadFinished
 at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1381)
 at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1395)
 at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:637)
 at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:616)
 at android.support.v4.app.DialogFragment.show(DialogFragment.java:139)
 at com.sankuai.common.views.MaoyanDialogBuilder.show(MaoyanDialogBuilder.java:185)
 at com.sankuai.movie.MovieMainActivity$8$1$1.onLoadFinished(MovieMainActivity.java:609)
 at com.sankuai.movie.MovieMainActivity$8$1$1.onLoadFinished(MovieMainActivity.java:590)
 at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:427)
 at android.support.v4.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:395)
 at android.support.v4.content.Loader.deliverResult(Loader.java:104)

二邻寿、原因

經(jīng)過(guò)查找污茵,發(fā)現(xiàn)這兩個(gè)Crash處于由同一個(gè)方法觸發(fā):

FragmentManagerImpl#checkStateLoss():
private void checkStateLoss() {
    if (mStateSaved) {
        throw new IllegalStateException(
                "Can not perform this action after onSaveInstanceState");
    }
    if (mNoTransactionsBecause != null) {
        throw new IllegalStateException(
                "Can not perform this action inside of " + mNoTransactionsBecause);
    }
}

這個(gè)方法中的每一個(gè)異常分別對(duì)應(yīng)了上述的兩段Crash Log渠抹。下面逐一分析蝙昙。

三闪萄、分析

第一部分:mStateSaved:

關(guān)于這個(gè)問(wèn)題,可以參考這篇文章奇颠,Fragment Transactions & Activity State Loss败去。

從代碼中可以看出,若這個(gè)字段為true烈拒,則會(huì)拋出異常圆裕。檢查代碼中與這個(gè)字段相關(guān)的內(nèi)容,如下:

Parcelable saveAllState() {
    // Make sure all pending operations have now been executed to get
    // our state update-to-date.
    execPendingActions();
 
    if (HONEYCOMB) {
        // As of Honeycomb, we save state after pausing.  Prior to that
        // it is before pausing.  With fragments this is an issue, since
        // there are many things you may do after pausing but before
        // stopping that change the fragment state.  For those older
        // devices, we will not at this point say that we have saved
        // the state, so we will allow them to continue doing fragment
        // transactions.  This retains the same semantics as Honeycomb,
        // though you do have the risk of losing the very most recent state
        // if the process is killed...  we'll live with that.
        mStateSaved = true;
    }
    ...
}
  
public void noteStateNotSaved() {
    mStateSaved = false;
}
 
public void dispatchCreate() {
    mStateSaved = false;
    moveToState(Fragment.CREATED, false);
}
 
public void dispatchActivityCreated() {
    mStateSaved = false;
    moveToState(Fragment.ACTIVITY_CREATED, false);
}
 
public void dispatchStart() {
    mStateSaved = false;
    moveToState(Fragment.STARTED, false);
}
 
public void dispatchResume() {
    mStateSaved = false;
    moveToState(Fragment.RESUMED, false);
}
 
public void dispatchPause() {
    moveToState(Fragment.STARTED, false);
}
 
public void dispatchStop() {
    // See saveAllState() for the explanation of this.  We do this for
    // all platform versions, to keep our behavior more consistent between
    // them.
    mStateSaved = true;
 
    moveToState(Fragment.STOPPED, false);
}

可以看到荆几,這個(gè)字段的使用與生命周期有關(guān)吓妆,隨便找一個(gè)生命周期的傳遞方法去查看使用:

會(huì)有三處使用到,分別研究

1)Fragment#getChildFragmentManager

/**
 * Return a private FragmentManager for placing and managing Fragments
 * inside of this Fragment.
 */
final public FragmentManager getChildFragmentManager() {
    if (mChildFragmentManager == null) {
        instantiateChildFragmentManager();
        if (mState >= RESUMED) {
            mChildFragmentManager.dispatchResume();
        } else if (mState >= STARTED) {
            mChildFragmentManager.dispatchStart();
        } else if (mState >= ACTIVITY_CREATED) {
            mChildFragmentManager.dispatchActivityCreated();
        } else if (mState >= CREATED) {
            mChildFragmentManager.dispatchCreate();
        }
    }
    return mChildFragmentManager;
}

這是在Fragment中獲取嵌套使用Fragment吨铸,獲取childFragmentManager時(shí)調(diào)用行拢,即告知childFragmentManager父Fragment當(dāng)前的生命周期。此時(shí)也會(huì)執(zhí)行childFragmentManager的初始化诞吱。

2)Fragment#performStart

void performStart() {
    if (mChildFragmentManager != null) {
        mChildFragmentManager.noteStateNotSaved();
        mChildFragmentManager.execPendingActions();
    }
    mCalled = false;
    onStart();
    if (!mCalled) {
        throw new SuperNotCalledException("Fragment " + this
                + " did not call through to super.onStart()");
    }
    if (mChildFragmentManager != null) {
        mChildFragmentManager.dispatchStart();
    }
    if (mLoaderManager != null) {
        mLoaderManager.doReportStart();
    }
}

這是在Fragmen在自己的生命周期變化過(guò)程中舟奠,通知子Fragment。

3)FragmentActivity#onStart

/**
 * Dispatch onStart() to all fragments.  Ensure any created loaders are
 * now started.
 */
@Override
protected void onStart() {
    super.onStart();
 
    mStopped = false;
    mReallyStopped = false;
    mHandler.removeMessages(MSG_REALLY_STOPPED);
 
    if (!mCreated) {
        mCreated = true;
        mFragments.dispatchActivityCreated();
    }
 
    mFragments.noteStateNotSaved();
    mFragments.execPendingActions();
     
    if (!mLoadersStarted) {
        mLoadersStarted = true;
        if (mLoaderManager != null) {
            mLoaderManager.doStart();
        } else if (!mCheckedForLoaderManager) {
            mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
            // the returned loader manager may be a new one, so we have to start it
            if ((mLoaderManager != null) && (!mLoaderManager.mStarted)) {
                mLoaderManager.doStart();
            }
        }
        mCheckedForLoaderManager = true;
    }
    // NOTE: HC onStart goes here.
     
    mFragments.dispatchStart();
    if (mAllLoaderManagers != null) {
        final int N = mAllLoaderManagers.size();
        LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
        for (int i=N-1; i>=0; i--) {
            loaders[i] = mAllLoaderManagers.valueAt(i);
        }
        for (int i=0; i<N; i++) {
            LoaderManagerImpl lm = loaders[i];
            lm.finishRetain();
            lm.doReportStart();
        }
    }
}

這是Activity在生命周期發(fā)生變化時(shí)房维,通知Fragment沼瘫。

現(xiàn)在了解了這個(gè)行為是和整個(gè)Activity、Fragment的生命周期有關(guān)的咙俩,回過(guò)頭再來(lái)看mStateSaved耿戚,這個(gè)字段是在onPause或者onStop之后就被置為true。在Android中暴浦,由于對(duì)運(yùn)行時(shí)的生命周期應(yīng)用能做的實(shí)在是很少溅话,用戶可以隨時(shí)切換Activity,系統(tǒng)也可以隨時(shí)回收處于后臺(tái)的Activity內(nèi)存歌焦,所以Android為了保證在再次返回Activity時(shí)讓它看起來(lái)同離開(kāi)時(shí)相似飞几,會(huì)使用onSaveInstanceState()來(lái)保存一些狀態(tài)。若在onSaveInstanceState()被調(diào)用之后調(diào)用FragmentTransaction#commit()独撇,那么這個(gè)Fragment的狀態(tài)就不會(huì)被保存屑墨,在之后恢復(fù)時(shí)也不會(huì)恢復(fù)這個(gè)Fragment,使得恢復(fù)時(shí)UI發(fā)生一些變化纷铣。
那為什么是onPause或者onStop之后被置為true卵史?這和Android的版本發(fā)展有關(guān),在HoneyComb之前搜立,Activity被設(shè)計(jì)成在onPause之前不會(huì)被殺掉以躯,所以onSaveInstanceState()是緊挨著onPause()之前調(diào)用的,但是在HoneyComb之后,Activity被設(shè)計(jì)成只有在onStop()之后才會(huì)被殺死忧设,所以onSaveInstanceState()會(huì)在onStop()之前刁标,而不是在onPause之前調(diào)用。

pre-Honeycomb
post-Honeycomb
Activities can be killed before onPause()?  NO  NO
Activities can be killed before onStop()?   YES NO
onSaveInstanceState(Bundle) is guaranteed to be called before...    onPause()   onStop()

由于這個(gè)原因址晕,若是在舊機(jī)型的onPause()之后調(diào)用FragmentTransaction#commit()膀懈,這個(gè)狀態(tài)就可能會(huì)丟失。這是由于Android開(kāi)發(fā)者為了避免過(guò)多的異常而做出的讓步谨垃,允許在onPause()和onStop()之間偶爾丟失commit()狀態(tài)启搂。

pre-Honeycomb
post-Honeycomb
commit() before onPause()   OK  OK
commit() between onPause() and onStop() STATE LOSS  OK
commit() after onStop() EXCEPTION   
EXCEPTION

應(yīng)當(dāng)注意的是,不僅僅是Activity的生命周期會(huì)影響刘陶,若使用的是嵌套在Fragment中的子Fragment胳赌,由上述代碼可知,也會(huì)有類似情況易核。

第二部分:mNoTransactionsBecause

再看一下FragmentManagerImpl#checkStateLoss()方法匈织,

private void checkStateLoss() {
    if (mStateSaved) {
        throw new IllegalStateException(
                "Can not perform this action after onSaveInstanceState");
    }
    if (mNoTransactionsBecause != null) {
        throw new IllegalStateException(
                "Can not perform this action inside of " + mNoTransactionsBecause);
    }
}

還有一個(gè)和StateLoss相關(guān)的字段是mNoTransactionsBecause,若這個(gè)字段不為空牡直,則拋出異常缀匕。先查看這個(gè)字段在哪里使用,或者說(shuō)碰逸,在什么情況下這個(gè)字段會(huì)不為空乡小。

可以看到調(diào)用的地方主要是兩個(gè)類,F(xiàn)ragmentManager 和 LoaderManager饵史,在FragmentManager中的使用都是用于拋出異常的满钟,并不在意這個(gè),而是在意何時(shí)不為空的胳喷,在LoaderManager中主要兩個(gè)地方為這個(gè)字段賦值:

1)destory

void destroy() {
    if (DEBUG) Log.v(TAG, "  Destroying: " + this);
    mDestroyed = true;
    boolean needReset = mDeliveredData;
    mDeliveredData = false;
    if (mCallbacks != null && mLoader != null && mHaveData && needReset) {
        if (DEBUG) Log.v(TAG, "  Reseting: " + this);
        String lastBecause = null;
        if (mActivity != null) {
            lastBecause = mActivity.mFragments.mNoTransactionsBecause;
            mActivity.mFragments.mNoTransactionsBecause = "onLoaderReset";
        }
        try {
            mCallbacks.onLoaderReset(mLoader);
        } finally {
            if (mActivity != null) {
                mActivity.mFragments.mNoTransactionsBecause = lastBecause;
            }
        }
    }
    mCallbacks = null;
    mData = null;
    mHaveData = false;
    if (mLoader != null) {
        if (mListenerRegistered) {
            mListenerRegistered = false;
            mLoader.unregisterListener(this);
        }
        mLoader.reset();
    }
    if (mPendingLoader != null) {
        mPendingLoader.destroy();
    }
}

2)callOnLoadFinished

void callOnLoadFinished(Loader<Object> loader, Object data) {
    if (mCallbacks != null) {
        String lastBecause = null;
        if (mActivity != null) {
            lastBecause = mActivity.mFragments.mNoTransactionsBecause;
            mActivity.mFragments.mNoTransactionsBecause = "onLoadFinished";
        }
        try {
            if (DEBUG) Log.v(TAG, "  onLoadFinished in " + loader + ": "
                    + loader.dataToString(data));
            mCallbacks.onLoadFinished(loader, data);
        } finally {
            if (mActivity != null) {
                mActivity.mFragments.mNoTransactionsBecause = lastBecause;
            }
        }
        mDeliveredData = true;
    }

在這兩個(gè)地方的考量湃番,也是由于loader的異步可能導(dǎo)致fragment在onSaveInstanceState()之后調(diào)用導(dǎo)致?tīng)顟B(tài)丟失。

四吭露、解決方案

那么如何解決這個(gè)問(wèn)題吠撮?

1)在LoaderManager.LoaderCallbacks#onLoadFinished 或者 LoaderManager.LoaderCallbacks#onLoaderReset中使用

這里直接使用commit()方法會(huì)直接拋出異常,需要加Handler避免在這兩個(gè)回調(diào)函數(shù)中直接使用commit()方法

2)在使用FragmentTransaction#commit()方法時(shí)注意當(dāng)前的生命周期讲竿。

一般而言泥兰,會(huì)在onCreate()或者響應(yīng)用戶的操作事件時(shí)才會(huì)使用commit()方法,這不會(huì)有問(wèn)題题禀,但假若在別的生命周期中使用就要小心了鞋诗。例如onActivityResult(), onStart(), 和 onResume(),就需要注意迈嘹。例如削彬,在onResume()中使用,但onResume()并不會(huì)保證在Activity狀態(tài)恢復(fù)之后調(diào)用,此時(shí)需要使用FragmentActivity#onResumeFragments()或者Activity#onPostResume()中調(diào)用吃警,這兩個(gè)會(huì)保證在狀態(tài)恢復(fù)之后調(diào)用糕篇。

3)避免異步回調(diào)中使用commit()方法

異步回調(diào),如AsyncTask#onPostExecute() 和 LoaderManager.LoaderCallbacks#onLoadFinished()酌心,之后無(wú)法保證當(dāng)前的生命狀態(tài),而且異步通常會(huì)執(zhí)行一些比較耗時(shí)的操作挑豌,更容易使得這樣的丟失發(fā)生安券,如用戶發(fā)出一個(gè)請(qǐng)求之后點(diǎn)了HOME鍵。

4)使用 commitAllowingStateLoss()方法

這個(gè)方法會(huì)跳過(guò)mStateSaved的檢查氓英,也不會(huì)在意會(huì)發(fā)生怎樣的影響侯勉,就算無(wú)法執(zhí)行或Activity狀態(tài)恢復(fù)之后發(fā)生了UI變動(dòng)也不會(huì)有警報(bào)。

5)針對(duì)DialogFragment的解決方案

由于DialogFragment和其它Fragment相比比較特殊铝阐,創(chuàng)建址貌、回收更頻繁也更不容易控制。

方法一:

對(duì)于DialogFragment而言徘键,只有show()方法而沒(méi)有showAllowingStateLoss()方法练对。。吹害。而且很多時(shí)候都需要在網(wǎng)絡(luò)請(qǐng)求返回之后根據(jù)返回的字段來(lái)顯示螟凭,所以最好在base中添加對(duì)Activity和Fragment的生命周期追蹤方法。但自己添加的方法和原生的畢竟在執(zhí)行時(shí)間上還是有一點(diǎn)時(shí)間差的它呀,不能夠100%避免crash螺男。

方法二:

或許有想法說(shuō)可以重寫(xiě)DialogFragment#show()方法,讓它支持commitAllowingStateLoss()纵穿,好吧下隧,來(lái)看下源碼。谓媒。淆院。這是show方法:

/**
 * Display the dialog, adding the fragment to the given FragmentManager.  This
 * is a convenience for explicitly creating a transaction, adding the
 * fragment to it with the given tag, and committing it.  This does
 * <em>not</em> add the transaction to the back stack.  When the fragment
 * is dismissed, a new transaction will be executed to remove it from
 * the activity.
 * @param manager The FragmentManager this fragment will be added to.
 * @param tag The tag for this fragment, as per
 * {@link FragmentTransaction#add(Fragment, String) FragmentTransaction.add}.
 */
public void show(FragmentManager manager, String tag) {
    mDismissed = false;
    mShownByMe = true;
    FragmentTransaction ft = manager.beginTransaction();
    ft.add(this, tag);
    ft.commit();
}
 
/**
 * Display the dialog, adding the fragment using an existing transaction
 * and then committing the transaction.
 * @param transaction An existing transaction in which to add the fragment.
 * @param tag The tag for this fragment, as per
 * {@link FragmentTransaction#add(Fragment, String) FragmentTransaction.add}.
 * @return Returns the identifier of the committed transaction, as per
 * {@link FragmentTransaction#commit() FragmentTransaction.commit()}.
 */
public int show(FragmentTransaction transaction, String tag) {
    mDismissed = false;
    mShownByMe = true;
    transaction.add(this, tag);
    mViewDestroyed = false;
    mBackStackId = transaction.commit();
    return mBackStackId;
}

可以看到,和普通的Fragment顯示方法區(qū)別并不大篙耗,其實(shí)DialogFragment只是一個(gè)Fragment里面套了個(gè)Dialog而已迫筑。但,有個(gè)很神奇的字段宗弯,mShownByMe脯燃,這個(gè)字段是做什么的?定義處和這里并沒(méi)有注釋蒙保,通過(guò)查找這個(gè)字段的使用辕棚,發(fā)現(xiàn)了這兩個(gè)方法:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    if (!mShownByMe) {
        // If not explicitly shown through our API, take this as an
        // indication that the dialog is no longer dismissed.
        mDismissed = false;
    }
}
 
@Override
public void onDetach() {
    super.onDetach();
    if (!mShownByMe && !mDismissed) {
        // The fragment was not shown by a direct call here, it is not
        // dismissed, and now it is being detached...  well, okay, thou
        // art now dismissed.  Have fun.
        mDismissed = true;
    }
}

通過(guò)這里可以發(fā)現(xiàn),這個(gè)字段是判斷DialogFragment是不是通過(guò)原生API的show()方法來(lái)顯示的。逝嚎。否則就不在onAttach()和onDetach()里設(shè)置mDismissed字段的扁瓢,再看onDetach里的注釋,為什么有種深深惡意补君。引几。(我辛辛苦苦寫(xiě)好了API,你為什么不用挽铁?你為什么不用伟桅?你為什么不用?(╯‵□′)╯︵┻━┻)
重寫(xiě)show()也是可以的叽掘,但需要緊接著重寫(xiě)onAttach()楣铁、onDetach()等方法。
若有需要重寫(xiě)show(FragmentTransaction transaction, String tag)方法更扁,除了mShownByMe字段還需要注意mViewDestroyed字段的值設(shè)置盖腕。

其實(shí)對(duì)于重寫(xiě)show()方法的弊端主要在于無(wú)法保證show()的執(zhí)行,從而導(dǎo)致isShowing()等方法的判斷不準(zhǔn)確浓镜,引起一些其他的問(wèn)題溃列。

方法三:

棄用DialogFragment。這種方法可以避免如此繁復(fù)的生命周期竖哩,代碼和使用簡(jiǎn)潔不少哭廉,但也少了 DialogFragment 的優(yōu)勢(shì),例如不能在切換屏幕時(shí)保留 Dialog 等相叁。

方法一的優(yōu)勢(shì)在于并不需要對(duì)DialogFragment的內(nèi)部實(shí)現(xiàn)做詳盡的了解遵绰,也避免了開(kāi)發(fā)者的惡意,但在onPause()之后增淹,onSaveInstanceState()之前的dialog都不會(huì)展示出來(lái)椿访。

方法二的優(yōu)勢(shì)在于API使用者并不需要在調(diào)用API的同時(shí)還為它的上下文環(huán)境擔(dān)驚受怕,但重寫(xiě)難度較大虑润,而且會(huì)有狀態(tài)丟失的情況成玫。

方法三也不是不可,只是有些問(wèn)題只適用 DialogFragment 解決拳喻,手動(dòng)實(shí)現(xiàn)會(huì)有很多變數(shù)哭当。

自行斟酌使用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末冗澈,一起剝皮案震驚了整個(gè)濱河市钦勘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌亚亲,老刑警劉巖彻采,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腐缤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡肛响,警方通過(guò)查閱死者的電腦和手機(jī)岭粤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)特笋,“玉大人剃浇,你說(shuō)我怎么就攤上這事”⒂校” “怎么了偿渡?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)霸奕。 經(jīng)常有香客問(wèn)我,道長(zhǎng)吉拳,這世上最難降的妖魔是什么质帅? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮留攒,結(jié)果婚禮上煤惩,老公的妹妹穿的比我還像新娘。我一直安慰自己炼邀,他們只是感情好魄揉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著拭宁,像睡著了一般洛退。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上杰标,一...
    開(kāi)封第一講書(shū)人閱讀 51,208評(píng)論 1 299
  • 那天兵怯,我揣著相機(jī)與錄音,去河邊找鬼腔剂。 笑死媒区,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的掸犬。 我是一名探鬼主播袜漩,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼湾碎!你這毒婦竟也來(lái)了宙攻?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤胜茧,失蹤者是張志新(化名)和其女友劉穎粘优,沒(méi)想到半個(gè)月后仇味,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡雹顺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年丹墨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嬉愧。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡贩挣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出没酣,到底是詐尸還是另有隱情王财,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布裕便,位于F島的核電站绒净,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏偿衰。R本人自食惡果不足惜挂疆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望下翎。 院中可真熱鬧缤言,春花似錦、人聲如沸视事。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)俐东。三九已至跌穗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間犬性,已是汗流浹背瞻离。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乒裆,地道東北人套利。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鹤耍,于是被迫代替她去往敵國(guó)和親肉迫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

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