Fragment(O)

fragment的作用这里不再多说,使用fragment的Activity继承于FragmentActivity(现在也统一继承AppCompatActivity,AppCompatActivity也同样继承于FragmentActivity),本篇以FragmentActivity为例

        mFragmentManager = getSupportFragmentManager();
        TestFragment testFragment = new TestFragment ();
        // 纯添加fragment
        mFragmentManager.beginTransaction()
                .add(R.id.main_content, testFragment , tag)
                .commitAllowingStateLoss();
        // 添加新fragment 隐藏旧的已隐藏的fragment
        mFragmentManager.beginTransaction()
                .add(R.id.main_content, fragment,tag)
                .hide(mCurrentFragment)
                .commit();
        // 显示某一个被隐藏的fragment 隐藏当前正在显示的fragment 
        mFragmentManager.beginTransaction()
                .show(fragment)
                .hide(mCurrentFragment)
                .commitAllowingStateLoss();

        // 加入回退栈
        transaction.addToBackStack(context.getClass().getName());
        // 按回退栈的顺序依次进行出栈(以返回键为例),当前Fragment进行出栈操作 
        getFragmentManager().popBackStack();
        // 回退到指定的Fragment;POP_BACK_STACK_INCLUSIVE跟Activity的SINGLE_TOP的效果
        // 一致  将栈中指定Fragment的上面的所有Fragment进行出栈操作
        fragmentManager.popBackStackImmediate(
        TestActivity.class.getName(), FragmentManager.POP_BACK_STACK_INCLUSIVE)

上面是最为常见的用法
ActivityThread在创建完Activity之后,会调用Activity的attach(),

// Activity#attach 
    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback) {
        attachBaseContext(context);
        mFragments.attachHost(null /*parent*/);
        mLastNonConfigurationInstances = lastNonConfigurationInstances;
        ...
        ... 代码省略 
    }

上面有一句mFragments.attachHost(null /*parent*/),mFragments是什么,他是FragmentController类型的,从名称可以看出这是一个Fragment的控制类,的确,他是用来管理Fragment的,也是FragmentManager的代理类,无论在Activity还是在FragmentActivity中都有一个默认的实现

// Activity || FragmentActivity#mFragments 
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

// FragmentController#createController
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
        return new FragmentController(callbacks);
    }
 //  FragmentController#FragmentController
private FragmentController(FragmentHostCallback<?> callbacks) {
        mHost = callbacks;
    }

我们先来看看HostCallbacks,其继承于FragmentHostCallback,FragmentHostCallback继承于FragmentContainer;FragmentHostCallback主要实现了一些fragment本身不能实现的功能,比如说根据viewid查找view,fragment跳转到一个新的Activity,请求权限等等;算是一个辅助类。

下面我们再来看attachHost():

   // FragmentController#attachHost
    public void attachHost(Fragment parent) {
        mHost.mFragmentManager.attachController(
                mHost, mHost /*container*/, parent);
    }
     mFragmentManager是FragmentManager的代理类,当然也统一由FragmentController 支配
     最终调用了FragmentManagerImpl的attachController

    // FragmentManagerImpl#attachController
    public void attachController(FragmentHostCallback host,
            FragmentContainer container, Fragment parent) {
        if (mHost != null) throw new IllegalStateException("Already attached");
        // mHost则是FragmentHostCallback  
        mHost = host;
        mContainer = container;
        // mParent则是根Fragment,这里为null
        mParent = parent;
    }
    

上面就是attach的流程,下面我们接着看create中的处理,

    // Activity#performCreate
    final void performCreate(Bundle icicle, PersistableBundle persistentState) {
        mCanEnterPictureInPicture = true;
        restoreHasCurrentPermissionRequest(icicle);
        if (persistentState != null) {
            onCreate(icicle, persistentState);
        } else {
            onCreate(icicle);
        }
      // 这里将FragmentManager的状态值修改为ACTIVITY_CREATED,即Activity创建的状态
        mFragments.dispatchActivityCreated();
    }

我们先来看onCreate():



// FragmentActivity#onCreate():
    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        // 这里又一次初始化FragmentManager
        mFragments.attachHost(null /*parent*/);
        // 这里调用Activity的onCreate(),下面会说
        super.onCreate(savedInstanceState);
        // 如果Activity状态发生了变化  
        if (savedInstanceState != null) {
            // 这里获取到Fragment保存的状态
            Parcelable p = savedInstanceState.getParcelable("android:support:fragments");
            // 这里通过FragmentManager进行处理(restoreAllState这里预留一个坑位,后面补上)
            mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
        }
        // 这里通过修改FragmentManager的状态为创建
        mFragments.dispatchCreate();
    }

我们再来看看 Activity#onCreate()
// Activity#onCreate():
    @MainThread
    @CallSuper
    protected void onCreate(@Nullable Bundle savedInstanceState) {
      
        if (savedInstanceState != null) {
      
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            // 可以看到这里 如果有fragment状态保存了的话,这里也是会调用restoreAllState
            mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                    ? mLastNonConfigurationInstances.fragments : null);
        }
        // 这里同样再次调用了 dispatchCreate
        mFragments.dispatchCreate();
    }

activity/fragment被异常销毁的情况放到最后再说,这里先跳过,我们来看调用了两次的dispatchCreate()

// FragmentController#dispatchCreate
    public void dispatchCreate() {
        mHost.mFragmentManager.dispatchCreate();
    }
// FragmentManager#dispatchCreate()
    public void dispatchCreate() {
        mStateSaved = false;
        mStopped = false;
        // 修改状态为CREATED
        dispatchStateChange(Fragment.CREATED);
    }
// FragmentManager#dispatchStateChange
    private void dispatchStateChange(int nextState) {
        try {
            mExecutingActions = true;
            moveToState(nextState, false);
        } finally {
            mExecutingActions = false;
        }
        // 这里主要是执行等待状态的Fragment,因为现在处理创建状态
        execPendingActions();
    }
// FragmentManager#moveToState
  void moveToState(int newState, boolean always) {
        // 
        if (mHost == null && newState != Fragment.INITIALIZING) {
            throw new IllegalStateException("No activity");
        }
        // 如果当前状态等于传入的状态直接返回,这也就是前面两次调用
        // dispatchCreate而不会冲突的原因 
        if (!always && newState == mCurState) {
            return;
        }

        mCurState = newState;
        // 这里第一次进入mActive == null
        if (mActive != null) {

            // Must add them in the proper order. mActive fragments may be out of order
            final int numAdded = mAdded.size();
            for (int i = 0; i < numAdded; i++) {
                Fragment f = mAdded.get(i);
                // 根据当前FragmentManager的状态,为Fragment执行相应的生命周期
                moveFragmentToExpectedState(f);
            }

            // Now iterate through all active fragments. These will include those that are removed
            // and detached.
            final int numActive = mActive.size();
            for (int i = 0; i < numActive; i++) {
                Fragment f = mActive.valueAt(i);
                if (f != null && (f.mRemoving || f.mDetached) && !f.mIsNewlyAdded) {
                    moveFragmentToExpectedState(f);
                }
            }
            // 执行等待中的Fragment 
            startPendingDeferredFragments();

            if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
                mHost.onSupportInvalidateOptionsMenu();
                mNeedMenuInvalidate = false;
            }
        }
    }
//  FragmentManager#moveFragmentToExpectedState
    void moveFragmentToExpectedState(Fragment f) {
        if (f == null) {
            return;
        }
        // 获取到当前FragmentManager的状态
        int nextState = mCurState;
        // 如果Fragment被移除销毁了,然后又重新添加执行的话 
        if (f.mRemoving) {
            if (f.isInBackStack()) {
                // 如果加入了回退栈  那么这个Fragment会从onCreate开始(这个标识代表onCreate)
                nextState = Math.min(nextState, Fragment.CREATED);
            } else {
                // 如果没有加入回退栈  那么这个Fragment从attach开始  (这个标识代表执行attach)
                nextState = Math.min(nextState, Fragment.INITIALIZING);
            }
        }
        // 为Fragment执行相应的声明周期  
        moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);
        // Fragment的显示与隐藏发生变化,这里做处理 
        if (f.mHiddenChanged) {
            completeShowHideFragment(f);
        }
    }

我们知道,对于fragment的添加,无论动态还是静态添加,fragment的生命周期总是在Activity的生命周期之后开始的,拿动态添加来说,我们在Activity#onResume()中进行Fragment的添加操作,那么Fragment的生命周期如何呢,我们常说的Fragment的声明都是跟随Activity生命周期的说法还成立么
我们来看moveToState()

    @SuppressWarnings("ReferenceEquality")
    void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {
        // Fragments that are not currently added will sit in the onCreate() state.
        if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
            // 如果任务栈中的Fragment还没有被添加,但是当前FragmentManger的状态值大于
            // CREATED 比如RESUMED状态,那我们就设置Fragement的状态为CREATED
            newState = Fragment.CREATED;
        }
        if (f.mRemoving && newState > f.mState) {
            // 如果Fragment被移除掉了,如果被加入到了回退栈那么设置Fragment的状态为CREATED
            // 否则 就设置Fragment的状态为当前FragmentManager的状态   
            if (f.mState == Fragment.INITIALIZING && f.isInBackStack()) {
                // Allow the fragment to be created so that it can be saved later.
                newState = Fragment.CREATED;
            } else {
                // While removing a fragment, we can't change it to a higher state.
                newState = f.mState;
            }
        }
        // Defer start if requested; don't allow it to move to STARTED or higher
        // if it's not already started.
        if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
            newState = Fragment.STOPPED;
        }
        // 如果Fragment的状态 小于当前FragmentManager的状态  即小于Activity的状态  
        if (f.mState <= newState) {
            if (f.mFromLayout && !f.mInLayout) {
                return;
            }
            if (f.getAnimatingAway() != null || f.getAnimator() != null) {
                f.setAnimatingAway(null);
                f.setAnimator(null);
                moveToState(f, f.getStateAfterAnimating(), 0, 0, true);
            }
            //  注意一下这个swich还有下面的那个  他们是没有break的,也就是说
            // 如果某一个条件成立的话 后面的条件都会被执行     
            switch (f.mState) {
                // 这里是Fragment首次添加的时候
                case Fragment.INITIALIZING:
                     // 每一个case下面都会有一个if判断 用于确保fragment 的生命
                    // 周期与Activity同步(至少不会超过)
                    if (newState > Fragment.INITIALIZING) {
                        if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
                        // 这里判断如果fragment保存了状态
                        if (f.mSavedFragmentState != null) {
                            f.mSavedFragmentState.setClassLoader(mHost.getContext()
                                    .getClassLoader());
                            // 回去各个状态 view状态,targetFragment等等
                            f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
                                    FragmentManagerImpl.VIEW_STATE_TAG);
                            f.mTarget = getFragment(f.mSavedFragmentState,
                                    FragmentManagerImpl.TARGET_STATE_TAG);
                            if (f.mTarget != null) {
                                f.mTargetRequestCode = f.mSavedFragmentState.getInt(
                                        FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
                            }
                            if (f.mSavedUserVisibleHint != null) {
                                f.mUserVisibleHint = f.mSavedUserVisibleHint;
                                f.mSavedUserVisibleHint = null;
                            } else {
                                f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
                                        FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
                            }
                            if (!f.mUserVisibleHint) {
                                f.mDeferStart = true;
                                if (newState > Fragment.STOPPED) {
                                    newState = Fragment.STOPPED;
                                }
                            }
                        }

                        f.mHost = mHost;
                        f.mParentFragment = mParent;
                        f.mFragmentManager = mParent != null
                                ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();

                        // If we have a target fragment, push it along to at least CREATED
                        // so that this one can rely on it as an initialized dependency.
                        if (f.mTarget != null) {
                            if (mActive.get(f.mTarget.mIndex) != f.mTarget) {
                                throw new IllegalStateException("Fragment " + f
                                        + " declared target fragment " + f.mTarget
                                        + " that does not belong to this FragmentManager!");
                            }
                            if (f.mTarget.mState < Fragment.CREATED) {
                                moveToState(f.mTarget, Fragment.CREATED, 0, 0, true);
                            }
                        }
                        // 调用attach之前的准备工作,主要是将当前生命周期的状
                        // 态分发出去,便于开发者做监听使用
                        dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
                        f.mCalled = false;
                        // 调用onAttach
                        f.onAttach(mHost.getContext());
                        if (!f.mCalled) {
                            throw new SuperNotCalledException("Fragment " + f
                                    + " did not call through to super.onAttach()");
                        }
                        if (f.mParentFragment == null) {
                            // 如果父Fragment为空,则将绑定fragment的监听回传
                            // 给Activity
                            mHost.onAttachFragment(f);
                        } else {
                           // 如果父Fragment不为空,那么就将监听回传给父Fragment
                        // 当然最终还是会回传给Activity
                            f.mParentFragment.onAttachFragment(f);
                        }
                        // 再次将Fragment的生命周期进行回调
                        dispatchOnFragmentAttached(f, mHost.getContext(), false);

                        //如果被启动的Fragment没有被创建,则调用onCreate
                        // 否则就恢复子FramentManager的状态
                        if (!f.mIsCreated) {
                            dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
                            f.performCreate(f.mSavedFragmentState);
                            dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
                        } else {
                            f.restoreChildFragmentState(f.mSavedFragmentState);
                            f.mState = Fragment.CREATED;
                        }
                        f.mRetaining = false;
                    }
                    // fall through
                case Fragment.CREATED:
                    // This is outside the if statement below on purpose; we want this to run
                    // even if we do a moveToState from CREATED => *, CREATED => CREATED, and
                    // * => CREATED as part of the case fallthrough above.
                    // 这里是调用onCreateView创建view,并调用ViewCreated()
                    // 以及生命周期的监听 
                    ensureInflatedFragmentView(f);
                    // 这个判断里面同样也是调用了跟上面方法一样的逻辑
                    // 不过多调用了一个onActivityCreated
                    if (newState > Fragment.CREATED) {
                        if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
                        if (!f.mFromLayout) {
                            ViewGroup container = null;
                            if (f.mContainerId != 0) {
                                if (f.mContainerId == View.NO_ID) {
                                    throwException(new IllegalArgumentException(
                                            "Cannot create fragment "
                                                    + f
                                                    + " for a container view with no id"));
                                }
                                container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
                                if (container == null && !f.mRestored) {
                                    String resName;
                                    try {
                                        resName = f.getResources().getResourceName(f.mContainerId);
                                    } catch (NotFoundException e) {
                                        resName = "unknown";
                                    }
                                    throwException(new IllegalArgumentException(
                                            "No view found for id 0x"
                                            + Integer.toHexString(f.mContainerId) + " ("
                                            + resName
                                            + ") for fragment " + f));
                                }
                            }
                            f.mContainer = container;
                            f.mView = f.performCreateView(f.performGetLayoutInflater(
                                    f.mSavedFragmentState), container, f.mSavedFragmentState);
                            if (f.mView != null) {
                                f.mInnerView = f.mView;
                                f.mView.setSaveFromParentEnabled(false);
                                if (container != null) {
                                    container.addView(f.mView);
                                }
                                if (f.mHidden) {
                                    f.mView.setVisibility(View.GONE);
                                }
                                f.onViewCreated(f.mView, f.mSavedFragmentState);
                                dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
                                        false);
                                // Only animate the view if it is visible. This is done after
                                // dispatchOnFragmentViewCreated in case visibility is changed
                                f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
                                        && f.mContainer != null;
                            } else {
                                f.mInnerView = null;
                            }
                        }

                        f.performActivityCreated(f.mSavedFragmentState);
                        dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
                        if (f.mView != null) {
                            f.restoreViewState(f.mSavedFragmentState);
                        }
                        f.mSavedFragmentState = null;
                    }
                    // fall through
                case Fragment.ACTIVITY_CREATED:
                    if (newState > Fragment.ACTIVITY_CREATED) {
                        f.mState = Fragment.STOPPED;
                    }
                    // fall through
                case Fragment.STOPPED:
                    if (newState > Fragment.STOPPED) {
                        if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                        f.performStart();
                        dispatchOnFragmentStarted(f, false);
                    }
                    // fall through
                case Fragment.STARTED:
                    if (newState > Fragment.STARTED) {
                        if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
                        f.performResume();
                        dispatchOnFragmentResumed(f, false);
                        f.mSavedFragmentState = null;
                        f.mSavedViewState = null;
                    }
            }
        } else if (f.mState > newState) {
            switch (f.mState) {
                case Fragment.RESUMED:
                    if (newState < Fragment.RESUMED) {
                        if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
                        f.performPause();
                        dispatchOnFragmentPaused(f, false);
                    }
                    // fall through
                case Fragment.STARTED:
                    if (newState < Fragment.STARTED) {
                        if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
                        f.performStop();
                        dispatchOnFragmentStopped(f, false);
                    }
                    // fall through
                case Fragment.STOPPED:
                    if (newState < Fragment.STOPPED) {
                        if (DEBUG) Log.v(TAG, "movefrom STOPPED: " + f);
                        f.performReallyStop();
                    }
                    // fall through
                case Fragment.ACTIVITY_CREATED:
                    if (newState < Fragment.ACTIVITY_CREATED) {
                        if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
                        if (f.mView != null) {
                            // Need to save the current view state if not
                            // done already.
                            if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
                                saveFragmentViewState(f);
                            }
                        }
                        f.performDestroyView();
                        dispatchOnFragmentViewDestroyed(f, false);
                        if (f.mView != null && f.mContainer != null) {
                            // Stop any current animations:
                            f.mContainer.endViewTransition(f.mView);
                            f.mView.clearAnimation();
                            AnimationOrAnimator anim = null;
                            if (mCurState > Fragment.INITIALIZING && !mDestroyed
                                    && f.mView.getVisibility() == View.VISIBLE
                                    && f.mPostponedAlpha >= 0) {
                                anim = loadAnimation(f, transit, false,
                                        transitionStyle);
                            }
                            f.mPostponedAlpha = 0;
                            if (anim != null) {
                                animateRemoveFragment(f, anim, newState);
                            }
                            f.mContainer.removeView(f.mView);
                        }
                        f.mContainer = null;
                        f.mView = null;
                        f.mInnerView = null;
                        f.mInLayout = false;
                    }
                    // fall through
                case Fragment.CREATED:
                    if (newState < Fragment.CREATED) {
                        if (mDestroyed) {
                            // The fragment's containing activity is
                            // being destroyed, but this fragment is
                            // currently animating away.  Stop the
                            // animation right now -- it is not needed,
                            // and we can't wait any more on destroying
                            // the fragment.
                            if (f.getAnimatingAway() != null) {
                                View v = f.getAnimatingAway();
                                f.setAnimatingAway(null);
                                v.clearAnimation();
                            } else if (f.getAnimator() != null) {
                                Animator animator = f.getAnimator();
                                f.setAnimator(null);
                                animator.cancel();
                            }
                        }
                        if (f.getAnimatingAway() != null || f.getAnimator() != null) {
                            // We are waiting for the fragment's view to finish
                            // animating away.  Just make a note of the state
                            // the fragment now should move to once the animation
                            // is done.
                            f.setStateAfterAnimating(newState);
                            newState = Fragment.CREATED;
                        } else {
                            if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
                            if (!f.mRetaining) {
                                f.performDestroy();
                                dispatchOnFragmentDestroyed(f, false);
                            } else {
                                f.mState = Fragment.INITIALIZING;
                            }

                            f.performDetach();
                            dispatchOnFragmentDetached(f, false);
                            if (!keepActive) {
                                if (!f.mRetaining) {
                                    makeInactive(f);
                                } else {
                                    f.mHost = null;
                                    f.mParentFragment = null;
                                    f.mFragmentManager = null;
                                }
                            }
                        }
                    }
            }
        }

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

上面的方法代码虽然多,但是逻辑很清楚,主要是为Fragment补齐生命周期,使之跟随Activity的声明周期
回到最初activity的attach(),其实在这个阶段,上面的好多方法都是不会执行的,为什么,因为Fragment本身还没有被创建,但是,activity的每一个生命周期都会去执行上面的流程,所以这里我就一股脑都梳理了一遍。
我们从Activity的创建开始,接着在Activity中创建了FragmentManager的代理,通过代理初始化FragmentManager,然后在根据Activity的生命周期,同步FragmentManager的生命周期,FragmentManager的每一次生命周期的状态改变,都会去处理其管理的Fragment的声明周期

接着Activity#performCreate往下看,执行完Activity#onCreate之后,调用 mFragments.dispatchActivityCreated(),这里的流程同上,只是FragmentManager状态修改为了ACTIVITY_CREATED,

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容