Fragment 生命周期源碼分析

  • 本次分析Fragment 1.3.4版本刻像,不同版本源碼會(huì)不同!
  • Fragment官方文檔
dependencies {
    val fragment_version = "1.3.4"

    // Java language implementation
    implementation("androidx.fragment:fragment:$fragment_version")
    // Kotlin
    implementation("androidx.fragment:fragment-ktx:$fragment_version")
    // Testing Fragments in Isolation
    debugImplementation("androidx.fragment:fragment-testing:$fragment_version")
}
  • Fragment 無論是單獨(dú)使用還是配合Viewpager杈曲,對(duì)于Android開發(fā)來說非常熟悉了楞艾,但生命周期,一般就網(wǎng)上看到的一張圖,想必大家也經(jīng)常看到;


    Fragment lifecyclee
  • 那Fragment的生命周期在什么時(shí)候調(diào)用的摩钙,commit之后怎么走到生命周期的每一個(gè)方法,需要看源碼才知道查辩,本文就此分析胖笛。

1.supportFragmentManager

  • 只有使用 FragmentActivity 才有 supportFragmentManager
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.test_activity3_activity)
    if (savedInstanceState == null) {
        supportFragmentManager.beginTransaction()
            .replace(R.id.container, TestActivity3Fragment.newInstance())
            .commitNow()
    }
}

1.1 getSupportFragmentManager

  • FragmentActivity里面的 mFragments 可不是Fragment數(shù)組哦宜岛,他是 FragmentController 长踊,這個(gè)很重要,先記住他萍倡。
     /* FragmentActivity類 */
     
     //創(chuàng)建FragmentController 
    final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

    /**
     * Return the FragmentManager for interacting with fragments associated
     * with this activity.
     */
    @NonNull
    public FragmentManager getSupportFragmentManager() {
        return mFragments.getSupportFragmentManager();
    }

1.2 FragmentController類

  • new HostCallbacks() 傳進(jìn)去身弊,再獲取 SupportFragmentManager。
public class FragmentController {
    private final FragmentHostCallback<?> mHost;

    /**
     * Returns a {@link FragmentController}.
     */
    @NonNull
    public static FragmentController createController(@NonNull FragmentHostCallback<?> callbacks) {
        return new FragmentController(checkNotNull(callbacks, "callbacks == null"));
    }

    private FragmentController(FragmentHostCallback<?> callbacks) {
        mHost = callbacks;
    }

    /**
     * 通過mHost獲取FragmentManager
     * Returns a {@link FragmentManager} for this controller.
     */
    @NonNull
    public FragmentManager getSupportFragmentManager() {
        return mHost.mFragmentManager;
    }
}

1.3 FragmentHostCallback類

  • FragmentHostCallback 里獲取 mFragmentManager列敲。
  • FragmentManagerImpl 繼承FragmentManager阱佛,但什么都沒做。
public abstract class FragmentHostCallback<E> extends FragmentContainer {
    @Nullable private final Activity mActivity;
    @NonNull private final Context mContext;
    @NonNull private final Handler mHandler;
    private final int mWindowAnimations;
    final FragmentManager mFragmentManager = new FragmentManagerImpl();
 }

//繼承FragmentManager戴而,但什么都沒做
class FragmentManagerImpl extends FragmentManager {
}
  • 到此就獲取一個(gè)fragmentManager凑术。

2.beginTransaction

  • 每次處理Fragment的事務(wù)都是新建一個(gè) BackStackRecord 回退棧 ,只能用一次填硕。
    @NonNull
    public FragmentTransaction beginTransaction() {
        return new BackStackRecord(this);
    }

2.1 FragmentTransaction類

  • BackStackRecord 類是繼承 抽象類FragmentTransaction麦萤,這里有非常重要的各個(gè)OP常量,還有內(nèi)部類OP扁眯。
  • add,hide,remove等操作也是在這個(gè)類,他們都會(huì)封裝進(jìn)Op翅帜,用數(shù)組mOps 保存姻檀。
public abstract class FragmentTransaction {

    static final int OP_NULL = 0;
    static final int OP_ADD = 1;
    static final int OP_REPLACE = 2;
    static final int OP_REMOVE = 3;
    static final int OP_HIDE = 4;
    static final int OP_SHOW = 5;
    static final int OP_DETACH = 6;
    static final int OP_ATTACH = 7;
    static final int OP_SET_PRIMARY_NAV = 8;
    static final int OP_UNSET_PRIMARY_NAV = 9;
    static final int OP_SET_MAX_LIFECYCLE = 10;
    .
    .
    ArrayList<Op> mOps = new ArrayList<>();
}

2.2 Op類

  • Op這個(gè)類對(duì)于后面add,hide,remove等操作很重要。
static final class Op {
        int mCmd;
        Fragment mFragment;
        int mEnterAnim;
        int mExitAnim;
        int mPopEnterAnim;
        int mPopExitAnim;
        Lifecycle.State mOldMaxState;
        Lifecycle.State mCurrentMaxState;

        Op() {
        }
        .
        .
}

2.3 BackStackRecord類

  • 這個(gè)類就是真正執(zhí)行提交事務(wù)的類涝滴,提交事務(wù)會(huì)把自己一起傳給FragmentManager绣版。
  • 還實(shí)現(xiàn)了 FragmentManager.OpGenerator 接口。
final class BackStackRecord extends FragmentTransaction implements
        FragmentManager.BackStackEntry, FragmentManager.OpGenerator {
       final FragmentManager mManager;

    @Override
    public int commit() {
        return commitInternal(false);
    }

    @Override
    public int commitAllowingStateLoss() {
        return commitInternal(true);
    }

    @Override
    public void commitNow() {
        disallowAddToBackStack();
        mManager.execSingleAction(this, false);
    }

    @Override
    public void commitNowAllowingStateLoss() {
        disallowAddToBackStack();
        mManager.execSingleAction(this, true);
    }
} 

3.add,hide,replace,remove

3.1 封裝歼疮,addOp

  • 這里就分析一個(gè)replace,其他也是差不多的杂抽。
  • 這里做的就是把要替換的控件id,fragment韩脏,tag缩麸,操作對(duì)應(yīng)的常量封裝進(jìn)Op類里。
/*FragmentTransaction*/

    /**
     * Calls {@link #replace(int, Fragment, String)} with a null tag.
     */
    @NonNull
    public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment) {
        return replace(containerViewId, fragment, null);
    }

    @NonNull
    public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment,
            @Nullable String tag)  {
        //判斷數(shù)據(jù)有效性
        if (containerViewId == 0) {
            throw new IllegalArgumentException("Must use non-zero containerViewId");
        }
        doAddOp(containerViewId, fragment, tag, OP_REPLACE);
        return this;
    }


    void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
       .
       .
        //封裝進(jìn)Op
        addOp(new Op(opcmd, fragment));
    }

    /**
     * mOps 數(shù)組保持著這些操作
     * 把fragment進(jìn)入退出動(dòng)畫一起加上赡矢,
     * 可以去setCustomAnimations方法看
     */
    void addOp(Op op) {
        mOps.add(op);
        op.mEnterAnim = mEnterAnim;
        op.mExitAnim = mExitAnim;
        op.mPopEnterAnim = mPopEnterAnim;
        op.mPopExitAnim = mPopExitAnim;
    }

4.commit

4.1 四種提交方式

  • 提交事務(wù)有四種杭朱,分別是阅仔,先不分析四種區(qū)別,不是本次重點(diǎn)弧械。
1. commit()
2. commitAllowingStateLoss()
3. commitNow()
4. commitNowAllowingStateLoss()

4.2 提交事務(wù)

  • commit 只能操作一次八酒,一次就把a(bǔ)dd,hide刃唐,replace等操作一起提交羞迷。
  • 提交事務(wù)其實(shí)就是把自己一起丟給FragmentManager執(zhí)行。
    @Override
    public int commit() {
        return commitInternal(false);
    }
    
    int commitInternal(boolean allowStateLoss) {
        //只能commit一次画饥,否則拋異常
        if (mCommitted) throw new IllegalStateException("commit already called");
        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
            Log.v(TAG, "Commit: " + this);
            LogWriter logw = new LogWriter(TAG);
            PrintWriter pw = new PrintWriter(logw);
            dump("  ", pw);
            pw.close();
        }
        mCommitted = true;
        //是否加入回退棧
        if (mAddToBackStack) {
            // 放入回退棧標(biāo)記的index
            mIndex = mManager.allocBackStackIndex();
        } else {
            mIndex = -1;
        }
        //操作入隊(duì)
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

4.3 handler 發(fā)送

  • commit 是在主線程異步執(zhí)行衔瓮,就是通過handler執(zhí)行。
 /*FragmentManager*/

    //保存操作
    private final ArrayList<OpGenerator> mPendingActions = new ArrayList<>();
 
    void enqueueAction(@NonNull OpGenerator action, boolean allowStateLoss) {
    
        if (!allowStateLoss) {
            if (mHost == null) {
                if (mDestroyed) {
                    //FragmentManager 已經(jīng) 銷毀
                    throw new IllegalStateException("FragmentManager has been destroyed");
                } else {
                    //FragmentManager 還沒綁定
                    throw new IllegalStateException("FragmentManager has not been attached to a "
                            + "host.");
                }
            }
            checkStateLoss();
        }
        //加鎖
        synchronized (mPendingActions) {
            if (mHost == null) {
                //commitAllowingStateLoss會(huì)走這里
                if (allowStateLoss) {
                    // This FragmentManager isn't attached, so drop the entire transaction.
                    return;
                }
                throw new IllegalStateException("Activity has been destroyed");
            }
            //加入到數(shù)組
            mPendingActions.add(action);
            //最終來到這里
            scheduleCommit();
        }
    }
  • 到這終于看到handler了,用post(Runnable)發(fā)送出去荒澡。
    void scheduleCommit() {
        synchronized (mPendingActions) {
            boolean postponeReady =
                    mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
            boolean pendingReady = mPendingActions.size() == 1;
            if (postponeReady || pendingReady) {
                //handler處理
                mHost.getHandler().removeCallbacks(mExecCommit);
                mHost.getHandler().post(mExecCommit);
                updateOnBackPressedCallbackEnabled();
            }
        }
    }

4.4 執(zhí)行execPendingActions

    private Runnable mExecCommit = new Runnable() {
        @Override
        public void run() {
            execPendingActions(true);
        }
    };

    /**
     * Only call from main thread!
     */
    boolean execPendingActions(boolean allowStateLoss) {
        ensureExecReady(allowStateLoss);

        boolean didSomething = false;
        //把事務(wù)放入臨時(shí)變量
        while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
            mExecutingActions = true;
            try { 
                //優(yōu)化整理事務(wù)           
                removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
            } finally {
                cleanupExec();
            }
            didSomething = true;
        }

        ...
        return didSomething;
    }

4.5 整理事務(wù)

  • removeRedundantOperationsAndExecute 有一大段注釋报辱,注釋的意思就是說這方法刪除冗余的操作,合并重復(fù)的操作单山,就是優(yōu)化整理
  • 重點(diǎn)看到 record.expandOps 方法碍现。
  • 拿出 Op 里面記錄的操作,對(duì)不同操作處理米奸,added增加或者移除昼接,替換就是先移除再添加,具體可以看源碼悴晰,這里就不貼全部了慢睡,有點(diǎn)多。
    /*FragmentManager*/
    
    /**
     * Remove redundant BackStackRecord operations and executes them. This method merges operations
     * of proximate records that allow reordering. See
    ...
     */
    private void removeRedundantOperationsAndExecute(@NonNull ArrayList<BackStackRecord> records,
            @NonNull ArrayList<Boolean> isRecordPop) {
      ...
      
      executeOpsTogether(records, isRecordPop, startIndex, recordNum);
        ...


    private void executeOpsTogether(@NonNull ArrayList<BackStackRecord> records,
            @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
       //展開整理
       oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);
    ...
}
    //展開整理
   Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
        for (int opNum = 0; opNum < mOps.size(); opNum++) {
            final Op op = mOps.get(opNum);
            switch (op.mCmd) {   
                //添加       
                case OP_ADD:
                case OP_ATTACH:
                    added.add(op.mFragment);
                    break;
                //移除
                case OP_REMOVE:
                case OP_DETACH: {
                    added.remove(op.mFragment);
                    if (op.mFragment == oldPrimaryNav) {
                        mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, op.mFragment));
                        opNum++;
                        oldPrimaryNav = null;
                    }
                }
                break;
                //替換
                case OP_REPLACE: {
                   ...
                }
                break;
                case OP_SET_PRIMARY_NAV: {
                   ...
                }
                break;
            }
        }
        return oldPrimaryNav;
    }

4.6 執(zhí)行事務(wù)

  • 這里的FragmentManager.executeOps方法铡溪,再進(jìn)入 BackStackRecord.executeOps方法漂辐,根據(jù)Op信息,處理再回到FragmentManager.moveToState方法棕硫。
    /*FragmentManager*/
    private void executeOpsTogether(@NonNull ArrayList<BackStackRecord> records,
            @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
        
        ...
        executeOps(records, isRecordPop, startIndex, endIndex);
        ...
}

    private static void executeOps(@NonNull ArrayList<BackStackRecord> records,
            @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
       ..
       record.executeOps();

    
    /*BackStackRecord*/
    void executeOps() {
        final int numOps = mOps.size();
        for (int opNum = 0; opNum < numOps; opNum++) {
            final Op op = mOps.get(opNum);
            final Fragment f = op.mFragment;
           ...
            switch (op.mCmd) {
                case OP_ADD:
                    f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                    mManager.setExitAnimationOrder(f, false);
                    mManager.addFragment(f);
                    break;
              .
              .
              .              
            }           
        }
        if (!mReorderingAllowed && !FragmentManager.USE_STATE_MANAGER) {
            // Added fragments are added at the end to comply with prior behavior.
            mManager.moveToState(mManager.mCurState, true);
        }
    }

4.7 狀態(tài)改變

  • 首先我們能看到Fragment 的狀態(tài)常量有哪些髓涯,其實(shí)有的版本,比如1.2.0只有5個(gè)哈扮,那這幾個(gè)怎么夠呢纬纪,好像生命周期不止這幾個(gè)啊,就是創(chuàng)建時(shí)正著來滑肉,銷毀時(shí)再反著來就行了包各。
public class Fragment implements ... {

    static final Object USE_DEFAULT_TRANSITION = new Object();

    static final int INITIALIZING = -1;          // Not yet attached.
    static final int ATTACHED = 0;               // Attached to the host.
    static final int CREATED = 1;                // Created.
    static final int VIEW_CREATED = 2;           // View Created.
    static final int AWAITING_EXIT_EFFECTS = 3;  // Downward state, awaiting exit effects
    static final int ACTIVITY_CREATED = 4;       // Fully created, not started.
    static final int STARTED = 5;                // Created and started, not resumed.
    static final int AWAITING_ENTER_EFFECTS = 6; // Upward state, awaiting enter effects
    static final int RESUMED = 7;                // Created started and resumed.

    int mState = INITIALIZING;
}
  • moveToState的代碼是本次關(guān)鍵。
  • newState = Math.min(newState, fragmentStateManager.computeExpectedState())靶庙,這里跟官方提供的懶加載有關(guān)问畅,可以限制fragment執(zhí)行到哪個(gè)階段,但現(xiàn)在先不管他。
  • if (f.mState <= newState) 按声,如果true , 可以看到后面的代碼是創(chuàng)建流程膳犹,比如 Fragment.INITIALIZING ,ATTACHED签则,CREATED等等须床,否則就是銷毀流程,這里就放一部分代碼渐裂,可以自己去源碼看看所有流程豺旬。
    void moveToState(int newState, boolean always) {
       ...
        moveFragmentToExpectedState(f);
       ...   
    }
    
    void moveFragmentToExpectedState(@NonNull Fragment f) {
        ...
        moveToState(f);
        ...
    }
    
    void moveToState(@NonNull Fragment f) {
        moveToState(f, mCurState);
    }

   void moveToState(@NonNull Fragment f, int newState) {
        //獲取FragmentStateManager 
        FragmentStateManager fragmentStateManager = mFragmentStore.getFragmentStateManager(f.mWho);
        if (fragmentStateManager == null) {
          
            fragmentStateManager = new FragmentStateManager(mLifecycleCallbacksDispatcher,
                    mFragmentStore, f);
           
            fragmentStateManager.setFragmentManagerState(Fragment.CREATED);
        }
     
        if (f.mFromLayout && f.mInLayout && f.mState == Fragment.VIEW_CREATED) {
            newState = Math.max(newState, Fragment.VIEW_CREATED);
        }
        //這里跟官方提供的懶加載有關(guān),可以限制fragment執(zhí)行到哪個(gè)階段
        newState = Math.min(newState, fragmentStateManager.computeExpectedState());
        if (f.mState <= newState) {
            // If we are moving to the same state, we do not need to give up on the animation.
            if (f.mState < newState && !mExitAnimationCancellationSignals.isEmpty()) {
                // The fragment is currently being animated...  but!  Now we
                // want to move our state back up.  Give up on waiting for the
                // animation and proceed from where we are.
                cancelExitAnimation(f);
            }
            switch (f.mState) {
                case Fragment.INITIALIZING:
                    if (newState > Fragment.INITIALIZING) {
                        fragmentStateManager.attach();
                    }
                    // fall through
                case Fragment.ATTACHED:
                    if (newState > Fragment.ATTACHED) {
                        fragmentStateManager.create();
                    }
                    // fall through
                case Fragment.CREATED:
                    // We want to unconditionally run this anytime we do a moveToState that
                    // moves the Fragment above INITIALIZING, including cases such as when
                    // we move from CREATED => CREATED as part of the case fall through above.
                    if (newState > Fragment.INITIALIZING) {
                        fragmentStateManager.ensureInflatedView();
                    }

                    if (newState > Fragment.CREATED) {
                        fragmentStateManager.createView();
                    }
                    // fall through
                ...
                
            }
        } else if (f.mState > newState) {
            switch (f.mState) {
                case Fragment.RESUMED:
                    if (newState < Fragment.RESUMED) {
                        fragmentStateManager.pause();
                    }
                    // fall through
                case Fragment.STARTED:
                    if (newState < Fragment.STARTED) {
                        fragmentStateManager.stop();
                    }
                    // fall through
                ...
            }
        }

        if (f.mState != newState) {
            if (isLoggingEnabled(Log.DEBUG)) {
                Log.d(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
                        + "expected state " + newState + " found " + f.mState);
            }
            f.mState = newState;
        }
    }

4.8 終于到fragment的生命周期執(zhí)行

  • 這里有一個(gè)FragmentStateManager柒凉,就是他才是真正的調(diào)用Fragment 的生命周期方法族阅,我們終于看到熟悉的身影,F(xiàn)ragment 的 onCreateView方法膝捞。
  • 這里看onCreateView 坦刀,我們最常用的方法,其他也是一樣樣的蔬咬,大家也可以嘗試自己去分析鲤遥。
 case Fragment.CREATED:                    
       if (newState > Fragment.CREATED) {
           fragmentStateManager.createView();
       }


    /*FragmentStateManager*/
     void createView() {
        ...
        mFragment.performCreateView(layoutInflater, container, mFragment.mSavedFragmentState);
        ...
     }

    /*Fragment*/
     void performCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        mChildFragmentManager.noteStateNotSaved();
        mPerformedCreateView = true;
        mViewLifecycleOwner = new FragmentViewLifecycleOwner(getViewModelStore());
        mView = onCreateView(inflater, container, savedInstanceState);
        if (mView != null) {
            // Initialize the view lifecycle
            mViewLifecycleOwner.initialize();
            // Tell the fragment's new view about it before we tell anyone listening
            // to mViewLifecycleOwnerLiveData and before onViewCreated, so that calls to
            // ViewTree get() methods return something meaningful
            ViewTreeLifecycleOwner.set(mView, mViewLifecycleOwner);
            ViewTreeViewModelStoreOwner.set(mView, mViewLifecycleOwner);
            ViewTreeSavedStateRegistryOwner.set(mView, mViewLifecycleOwner);
            // Then inform any Observers of the new LifecycleOwner
            mViewLifecycleOwnerLiveData.setValue(mViewLifecycleOwner);
        } else {
            if (mViewLifecycleOwner.isInitialized()) {
                throw new IllegalStateException("Called getViewLifecycleOwner() but "
                        + "onCreateView() returned null");
            }
            mViewLifecycleOwner = null;
        }
    }

5.流程圖

  • 搭配流程圖看可能會(huì)好一些。


    流程圖
  • 如果有錯(cuò)幫忙指出林艘,謝謝盖奈。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市狐援,隨后出現(xiàn)的幾起案子钢坦,更是在濱河造成了極大的恐慌,老刑警劉巖啥酱,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爹凹,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡镶殷,警方通過查閱死者的電腦和手機(jī)逛万,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來批钠,“玉大人,你說我怎么就攤上這事得封÷裥模” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵忙上,是天一觀的道長(zhǎng)拷呆。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么茬斧? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任腰懂,我火速辦了婚禮,結(jié)果婚禮上项秉,老公的妹妹穿的比我還像新娘绣溜。我一直安慰自己,他們只是感情好娄蔼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布怖喻。 她就那樣靜靜地躺著,像睡著了一般岁诉。 火紅的嫁衣襯著肌膚如雪锚沸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天涕癣,我揣著相機(jī)與錄音哗蜈,去河邊找鬼。 笑死坠韩,一個(gè)胖子當(dāng)著我的面吹牛距潘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播同眯,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼绽昼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了须蜗?” 一聲冷哼從身側(cè)響起硅确,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎明肮,沒想到半個(gè)月后菱农,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡柿估,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年循未,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秫舌。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡的妖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出足陨,到底是詐尸還是另有隱情嫂粟,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布墨缘,位于F島的核電站星虹,受9級(jí)特大地震影響零抬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宽涌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一平夜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧卸亮,春花似錦忽妒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至寝受,卻和暖如春坷牛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背很澄。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工京闰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人甩苛。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓蹂楣,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親讯蒲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子痊土,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

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