ViewPager刷新問題原理分析及解決方案(FragmentPagerAdapter+FragementStatePagerAdapter)

Android開發(fā)中經(jīng)常用到ViewPager+Fragment+Adapter的場(chǎng)景,一般每個(gè)Fragment控制自己的刷新局蚀,但是如果想要刷新整個(gè)ViewPager怎么做呢麦锯?或者想要將緩存的Fragent給重建怎么做呢?之前做業(yè)務(wù)的時(shí)候遇到一個(gè)問題琅绅,ViewPage在第二次setAdapter的如果用的是FragmentPager并不會(huì)導(dǎo)致頁面刷新扶欣,但是采用FragementStatePagerAdapter卻會(huì)刷新?不由得有些好奇千扶,隨跟蹤了部分源碼料祠,簡(jiǎn)單整理如下:

ViewPager+FragmentPagerAdapter為何不能通過setAdapter做到整體刷新

第二次設(shè)置PagerAdapter的時(shí)候,首先會(huì)將原來的Fragment進(jìn)行清理澎羞,之后在調(diào)用populate()重建髓绽,只是重建的時(shí)候并不一定真的重新創(chuàng)建Fragment,如下:

public void setAdapter(PagerAdapter adapter) {
    if (mAdapter != null) {
        ...
        for (int i = 0; i < mItems.size(); i++) {
            final ItemInfo ii = mItems.get(i);
            <!--全部destroy-->
            mAdapter.destroyItem(this, ii.position, ii.object);
        }
        mAdapter.finishUpdate(this);
        <!--清理-->
        mItems.clear();
        removeNonDecorViews();
        <!--重置位置-->
        mCurItem = 0;
        scrollTo(0, 0);
    }
    ...
    if (!wasFirstLayout) {
    <!--重新設(shè)置Fragment-->
       populate();
       }
    ...   
    }        

之前說過妆绞,第二次通過setAdapter的方式來設(shè)置ViewPager的FragmentAdapter時(shí)不會(huì)立即刷新的效果顺呕,但是如果往后滑動(dòng)幾屏?xí)l(fā)現(xiàn)其實(shí)是有效果了?為什么呢括饶,因?yàn)榈诙蝧etAdapter的時(shí)候塘匣,已經(jīng)被FragmentManager緩存的Fragent不會(huì)被新建,也不會(huì)被刷新巷帝,因?yàn)镕ragmentPagerAdapter在調(diào)用destroy的時(shí)候,采用的是detach的方式扫夜,并未真正的銷毀Fragment楞泼,僅僅是打算銷毀了View,這就導(dǎo)致FragmentManager中仍舊保留正Fragment的緩存:

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    if (mCurTransaction == null) {
        mCurTransaction = mFragmentManager.beginTransaction();
    }
    // 僅僅detach
    mCurTransaction.detach((Fragment)object);
}

Transaction.detach函數(shù)最終會(huì)調(diào)用FragmentManager的detachFragment函數(shù)笤闯,將Fragment從當(dāng)前Activity detach

     public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
    if (!fragment.mDetached) {
        <!--只是detach -->
        fragment.mDetached = true;
        if (fragment.mAdded) {
        <!--如果是被added 從added列表中移除-->
            if (mAdded != null) {
                mAdded.remove(fragment);
            }
            ...
            fragment.mAdded = false;
            <!--將狀態(tài)設(shè)置為Fragment.CREATED-->
            moveToState(fragment, Fragment.CREATED, transition, transitionStyle, false);
        }
    }
}

可以看到堕阔,這里僅僅會(huì)將Fragment設(shè)置為Fragment.CREATED,對(duì)于Fragment.CREATED狀態(tài)的Fragment颗味,F(xiàn)ragmentManager是不會(huì)調(diào)用makeInactive進(jìn)行清理的超陆,

void moveToState(Fragment f, int newState, int transit, int transitionStyle,
        boolean keepActive) {
        ...
 case Fragment.CREATED:
         if (newState < Fragment.CREATED) {
             ...
                if (!keepActive) {
                    if (!f.mRetaining) {
                        makeInactive(f);
                    } else {
                        f.mActivity = null;
                        f.mParentFragment = null;
                        f.mFragmentManager = null;
                    }
               ...

因?yàn)橹挥衜akeInactive才會(huì)清理Fragment的引用如下:

void makeInactive(Fragment f) {
    if (f.mIndex < 0) {
        return;
    }
    <!--置空mActive列表對(duì)于Fragment的強(qiáng)引用-->
    mActive.set(f.mIndex, null);
    if (mAvailIndices == null) {
        mAvailIndices = new ArrayList<Integer>();
    }
    mAvailIndices.add(f.mIndex);
    mActivity.invalidateFragment(f.mWho);
    f.initState();
}

可見,F(xiàn)ragment的緩存仍舊留在FragmentManager中。新的FragmentPagerAdapter被設(shè)置后时呀,會(huì)通過instantiateItem函數(shù)來獲取Fragment张漂,這個(gè)時(shí)候它首先會(huì)從FragmentManager的緩存中去取Fragment,取到的Fragment其實(shí)就是之前未銷毀的Fragment谨娜,就會(huì)導(dǎo)致之前傳遞的參數(shù)仍然是舊的航攒,這也是為什么可能不會(huì)刷新的原因:

@Override
public Object instantiateItem(ViewGroup container, int position) {
    <!--新建一個(gè)事務(wù)-->
    if (mCurTransaction == null) {
        mCurTransaction = mFragmentManager.beginTransaction();
    }
    final long itemId = getItemId(position);
    <!--利用id與container的id創(chuàng)建name-->
    String name = makeFragmentName(container.getId(), itemId);
    <!--根據(jù)name在Activity的FragmentManager中查找緩存Fragment-->
    Fragment fragment = mFragmentManager.findFragmentByTag(name);
    <!--如果找到的話,直接使用當(dāng)前Fragment-->
    if (fragment != null) {
        mCurTransaction.attach(fragment);
    } else {
    <!--如果找不到則新建趴梢,并新建name漠畜,添加到container中去-->
        fragment = getItem(position);
        mCurTransaction.add(container.getId(), fragment,
                makeFragmentName(container.getId(), itemId));
    }
    if (fragment != mCurrentPrimaryItem) {
        fragment.setMenuVisibility(false);
        fragment.setUserVisibleHint(false);
    }
   return fragment;
}

從上面代碼可以看到,在新建Fragment對(duì)象的時(shí)候坞靶,首先是通過mFragmentManager.findFragmentByTag(name);查找是否已經(jīng)有Fragment緩存憔狞,第二次設(shè)置Adapter的時(shí)候,由于部分Fragment已經(jīng)被添加到FragmentManager的緩存中去了彰阴,新的Adapter仍然能通過mFragmentManager.findFragmentByTag(name)找到緩存Fragment瘾敢,阻止了Fragment的新建,因此不會(huì)有整體刷新的效果硝枉。那如果想要整體刷新怎么辦呢廉丽?可以使用FragementStatePagerAdapter,兩者對(duì)于Fragment的緩存管理不同妻味。

ViewPager+FragementStatePagerAdapter可以通過setAdapter做到整體刷新

同樣先看一下FragementStatePagerAdapter的destroyItem函數(shù)正压,F(xiàn)ragementStatePagerAdapter在destroyItem的時(shí)候使用的是remove的方式,這種方式對(duì)于沒有添加到回退棧的Fragment操作來說责球,不僅會(huì)銷毀view焦履,還會(huì)銷毀Fragment。

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    Fragment fragment = (Fragment)object;

    if (mCurTransaction == null) {
        mCurTransaction = mFragmentManager.beginTransaction();
    }
   while (mSavedState.size() <= position) {
        mSavedState.add(null);
    }
    mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment));
    <!--FragementStatePagerAdapter先清理自己的緩存-->
    mFragments.set(position, null);
    <!--直接刪除-->
    mCurTransaction.remove(fragment);
}

可見FragementStatePagerAdapter會(huì)首先通過mFragments.set(position, null)清理自己的緩存雏逾,然后嘉裤,通過Transaction.remove清理在FragmentManager中的緩存,Transaction.remove最終會(huì)調(diào)用FragmentManager的removeFragment函數(shù):

public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
<!-- 其實(shí)兩者的主要區(qū)別就是看是否在回退棧栖博,如果在屑宠,表現(xiàn)就一致,如果不在仇让,表現(xiàn)不一致-->
    final boolean inactive = !fragment.isInBackStack();
    if (!fragment.mDetached || inactive) {
        if (mAdded != null) {
            mAdded.remove(fragment);
        }
        ...
        fragment.mAdded = false;
        fragment.mRemoving = true;
        <!--將狀態(tài)設(shè)置為Fragment.CREATED或者Fragment.INITIALIZING-->
        moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
                transition, transitionStyle, false);
    }
}

FragementStatePagerAdapter中的Fragment在添加的時(shí)候典奉,都沒有addToBackStack,所以moveToState會(huì)將狀態(tài)設(shè)置為Fragment.INITIALIZING 丧叽,

void moveToState(Fragment f, int newState, int transit, int transitionStyle,
        boolean keepActive) {
        ...
 case Fragment.CREATED:
         if (newState < Fragment.CREATED) {
             ...
                if (!keepActive) {
                    if (!f.mRetaining) {
                        makeInactive(f);
                    } else {
                        f.mActivity = null;
                        f.mParentFragment = null;
                        f.mFragmentManager = null;
                    }
               ...

Fragment.INITIALIZING < Fragment.CREATED卫玖,這里一般會(huì)調(diào)用makeInactive函數(shù)清理Fragment的引用,這里其實(shí)就算銷毀了Fragment在FragmentManager中的緩存踊淳。

ViewPager通過populate因此再次新建的時(shí)候假瞬,F(xiàn)ragementStatePagerAdapter的instantiateItem 一定會(huì)新建Fragment,因?yàn)橹暗腇ragment已經(jīng)被清理掉了,在自己的Fragment緩存列表中取不到脱茉,就新建剪芥。看如下代碼:

    @Override
public Object instantiateItem(ViewGroup container, int position) {
    <!--查看FragementStatePagerAdapter中是否有緩存的Fragment芦劣,如果有直接返回-->
    if (mFragments.size() > position) {
        Fragment f = mFragments.get(position);
        if (f != null) {
            return f;
        }
    }
   ...
     <!--關(guān)鍵點(diǎn)   如果在FragementStatePagerAdapter找不到粗俱,直接新建,不關(guān)心FragmentManager中是否有-->
    Fragment fragment = getItem(position);
    <!--查看是否需恢復(fù)虚吟,如果需要寸认,則恢復(fù)-->
    if (mSavedState.size() > position) {
        Fragment.SavedState fss = mSavedState.get(position);
        if (fss != null) {
            fragment.setInitialSavedState(fss);
        }
    }
    ...
    mFragments.set(position, fragment);
    mCurTransaction.add(container.getId(), fragment);

    return fragment;
}

從上面代碼也可以看出,F(xiàn)ragementStatePagerAdapter在新建Fragment的時(shí)候串慰,不會(huì)去FragmentMangerImpl中去取偏塞,而是直接在FragementStatePagerAdapter的緩存中取,如果取不到邦鲫,則直接新建Fragment灸叼,如果通過setAdapter設(shè)置了新的FragementStatePagerAdapter,一定會(huì)新建所有的Fragment庆捺,就能夠達(dá)到整體刷新的效果古今。

FragmentPagerAdapter如何通過notifyDataSetChanged刷新ViewPager

FragmentPagerAdapter中的數(shù)據(jù)發(fā)生改變時(shí),往往要重新將數(shù)據(jù)設(shè)置到Fragment滔以,或者干脆新建Fragment捉腥,而對(duì)于用FragmentPagerAdapter的ViewPager來說,只是利用其notifyDataSetChanged是不夠的你画,跟蹤源碼會(huì)發(fā)現(xiàn)抵碟,notifyDataSetChanged最終會(huì)調(diào)用ViewPager中的dataSetChanged:

notifyDataSetChanged流程
void dataSetChanged() {
    ...
    for (int i = 0; i < mItems.size(); i++) {
        final ItemInfo ii = mItems.get(i);
        final int newPos = mAdapter.getItemPosition(ii.object);
       if (newPos == PagerAdapter.POSITION_UNCHANGED) {
            continue;
        }
       if (newPos == PagerAdapter.POSITION_NONE) {
            mItems.remove(i);
            i--;
           ...
           mAdapter.destroyItem(this, ii.position, ii.object);
            needPopulate = true;
           ...
            continue;
        }
    ...
    if (needPopulate) {
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = getChildAt(i);
            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
            if (!lp.isDecor) {
                lp.widthFactor = 0.f;
            }
        }
        setCurrentItemInternal(newCurrItem, false, true);
        requestLayout();
    }
}

默認(rèn)情況下FragmentPagerAdapter中的getItemPosition返回的是PagerAdapter.POSITION_UNCHANGED,所以這里不會(huì)
destroyItem坏匪,即時(shí)設(shè)置了PagerAdapter.POSITION_NONE拟逮,調(diào)用了其destroyItem,也僅僅是detach适滓,銷毀了View敦迄,F(xiàn)ragment仍舊不會(huì)重建,必須手動(dòng)更改參數(shù)才可以凭迹,這個(gè)時(shí)機(jī)在哪里呢罚屋?FragmentAdapter的getItem函數(shù)會(huì)在第一次需要?jiǎng)?chuàng)建Fragment的時(shí)候調(diào)用,如果需要將參數(shù)傳遞給Fragment蕊苗,可以通過Fragment.setArguments()來設(shè)置,但是僅僅在getItem新建的時(shí)候有效沿彭,一旦被Fragment被創(chuàng)建朽砰,就會(huì)被FragmentManager緩存,如果不主動(dòng)釋放,對(duì)于當(dāng)前位置的Fragment來說瞧柔,getItem函數(shù)是不會(huì)再次被調(diào)用的漆弄,原因已經(jīng)在上文的instantiateItem函數(shù)處說明了,它會(huì)首先去緩存中取造锅。那這個(gè)時(shí)候撼唾,如何更新呢?Fragment.setArguments是不能再調(diào)用的哥蔚,因?yàn)楸籥ttach過的Fragment來說不能再次通過setArguments被設(shè)置參數(shù)倒谷,否則拋出異常

public void setArguments(Bundle args) {
    if (mIndex >= 0) {
        throw new IllegalStateException("Fragment already active");
    }
    mArguments = args;
}

那如果真要更改就需要在其instantiateItem的時(shí)候强经,通過額外的接口手動(dòng)設(shè)置俯艰,同時(shí)也必須將getItemPosition返回值設(shè)置為POSITION_NONE,這樣才會(huì)每次都走View的新建流程碴卧,才有可能刷新:

public int getItemPosition(Object object) {
    return POSITION_NONE;
}

至于參數(shù)如何設(shè)置呢深夯?這里就需要用戶手動(dòng)提供接口變更參數(shù)了抖格,在自定義的FragmentAdapter覆蓋instantiateItem,自己手動(dòng)獲取緩存Fragment咕晋,在attach之前雹拄,將參數(shù)給重新設(shè)置進(jìn)去,之后掌呜,F(xiàn)ragment在走onCreateView流程的時(shí)候滓玖,就會(huì)獲取到新的參數(shù)。

@Override
public Object instantiateItem(ViewGroup container, int position) {

    String name = makeFragmentName(container.getId(), position);
    Fragment fragment =((FragmentActivity) container.getContext()).getSupportFragmentManager().findFragmentByTag(name);

    if(fragment instanceof MyFragment){
        Bundle bundle=new Bundle();
        bundle.putString("msg",""+System.currentTimeMillis());
        ( (MyFragment) fragment).resetArgument(bundle);
    }

    return super.instantiateItem(container, position);
}

private static String makeFragmentName(int viewId, long id) {
    return "android:switcher:" + viewId + ":" + id;
}

如此站辉,便可以完成FragmentPagerAdapter中Fragment的刷新呢撞。并且到這里我們也知道了,對(duì)于FragmentPagerAdapter來說饰剥,用戶完全不需要自己緩存Fragment殊霞,只需要緩存View,因?yàn)镕ragmentPagerAdapter不會(huì)銷毀Fragment汰蓉,也不會(huì)銷毀FragmentManager中緩存的Fragment绷蹲,至于緩存的View要不要刷新,可能就要你具體的業(yè)務(wù)需求了顾孽。

FragmentStatePagerAdapter如何通過notifyDataSetChanged刷新ViewPager頁面

對(duì)于FragmentStatePagerAdapter相對(duì)容易些祝钢,如果不需要考慮效率,重建所有的Fragment即可若厚,只需要復(fù)寫其getItemPosition函數(shù)

public int getItemPosition(Object object) {
    return POSITION_NONE;
}

因?yàn)镕ragmentStatePagerAdapter中會(huì)真正的remove Fragment拦英,達(dá)到完全重建的效果。

Fragmentmanager Transaction棧的意義

最后看一下Fragmentmanager中Transaction棧测秸,F(xiàn)ragmentManager的Transaction棧到底是做什么的呢疤估?FragmentManager對(duì)于Fragment的操作是分批量進(jìn)行的灾常,在一個(gè)Transaction中有多個(gè)add、remove铃拇、attach操作钞瀑,Android是有返回鍵的,為了支持點(diǎn)擊返回鍵恢復(fù)上一個(gè)場(chǎng)景的操作慷荔,Android的Fragment管理引入Transaction棧雕什,更方便回退,其實(shí)將一個(gè)Transaction的操作全部翻轉(zhuǎn):添加變刪除显晶、attach變detach贷岸,反之亦然。對(duì)于每個(gè)入棧的Transaction吧碾,都是需要出棧的凰盔,而且每個(gè)操作都有前后文,比如進(jìn)入與退出的動(dòng)畫倦春,當(dāng)需要翻轉(zhuǎn)這個(gè)操作户敬,也就是點(diǎn)擊返回鍵的時(shí)候,需要知道如何翻轉(zhuǎn)睁本,也就是需要記錄當(dāng)前場(chǎng)景尿庐,對(duì)于remove,如果沒有入棧操作呢堰,說明不用記錄上下文抄瑟,可以直接清理掉。對(duì)于ViewPager在使用FragmentPagerAdapter/FragmentStatePagerAdapter的時(shí)候都不會(huì)addToBackStack枉疼,這也是為什么detach跟remove有時(shí)候表現(xiàn)一致或者不一致的原因皮假。簡(jiǎn)單看一下出棧操作,其實(shí)就是將原來從操作翻轉(zhuǎn)一遍骂维,當(dāng)然惹资,并不是完全照搬,還跟當(dāng)前的Fragment狀體有關(guān)航闺。

public void popFromBackStack(boolean doStateMove) {
   Op op = mTail;
    while (op != null) {
        switch (op.cmd) {
            case OP_ADD: {
                Fragment f = op.fragment;
                f.mNextAnim = op.popExitAnim;
                mManager.removeFragment(f,
                        FragmentManagerImpl.reverseTransit(mTransition),
                        mTransitionStyle);
            } break;
            case OP_REPLACE: {
                Fragment f = op.fragment;
                if (f != null) {
                    f.mNextAnim = op.popExitAnim;
                    mManager.removeFragment(f,
                            FragmentManagerImpl.reverseTransit(mTransition),
                            mTransitionStyle);
                }
                if (op.removed != null) {
                    for (int i=0; i<op.removed.size(); i++) {
                        Fragment old = op.removed.get(i);
                        old.mNextAnim = op.popEnterAnim;
                        mManager.addFragment(old, false);
                    }
                }
            } break;
            ...

FragmentManager對(duì)于Fragment的緩存管理

FragmentManager主要維護(hù)三個(gè)重要List褪测,一個(gè)是mActive Fragment列表,一個(gè)是mAdded FragmentList潦刃,還有個(gè)BackStackRecord回退棧

ArrayList<Fragment> mActive;
ArrayList<Fragment> mAdded;
ArrayList<BackStackRecord> mBackStack;

mAdded列表是被當(dāng)前添加到Container中去的侮措,而mActive是全部參與的Fragment集合,只要沒有被remove乖杠,就會(huì)一致存在分扎,可以認(rèn)為mAdded的Fragment都是活著的,而mActive的Fragment卻可能被處決胧洒,并被置null畏吓,只有makeInactive函數(shù)會(huì)這么做环揽。

void makeInactive(Fragment f) {
    if (f.mIndex < 0) {
        return;
    }
    mActive.set(f.mIndex, null);
    if (mAvailIndices == null) {
        mAvailIndices = new ArrayList<Integer>();
    }
    mAvailIndices.add(f.mIndex);
    mActivity.invalidateFragment(f.mWho);
    f.initState();
}

FragmentPagerAdapter獲取試圖獲取的Fragment就是從這兩個(gè)列表中讀取的 。

public Fragment findFragmentByTag(String tag) {
    if (mAdded != null && tag != null) {
        for (int i=mAdded.size()-1; i>=0; i--) {
            Fragment f = mAdded.get(i);
            if (f != null && tag.equals(f.mTag)) {
                return f;
            }
        }
    }
    if (mActive != null && tag != null) {
        for (int i=mActive.size()-1; i>=0; i--) {
            Fragment f = mActive.get(i);
            if (f != null && tag.equals(f.mTag)) {
                return f;
            }
        }
    }
    return null;
}    

總結(jié)

本文簡(jiǎn)單分析了下ViewPager在使用FrgmentPagerAdapter跟FragmentStatePagerAdapter遇到問題庵佣,原理、及問題的解決方案汛兜。

作者:看書的小蝸牛
原文鏈接:ViewPager刷新問題原理分析及解決方案(FragmentPagerAdapter+FragementStatePagerAdapter)

僅供參考巴粪,歡迎指正

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市粥谬,隨后出現(xiàn)的幾起案子肛根,更是在濱河造成了極大的恐慌,老刑警劉巖漏策,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件派哲,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡掺喻,警方通過查閱死者的電腦和手機(jī)芭届,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來感耙,“玉大人褂乍,你說我怎么就攤上這事〖磁穑” “怎么了逃片?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)只酥。 經(jīng)常有香客問我褥实,道長(zhǎng),這世上最難降的妖魔是什么裂允? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任损离,我火速辦了婚禮,結(jié)果婚禮上叫胖,老公的妹妹穿的比我還像新娘草冈。我一直安慰自己,他們只是感情好瓮增,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布怎棱。 她就那樣靜靜地躺著,像睡著了一般绷跑。 火紅的嫁衣襯著肌膚如雪拳恋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天砸捏,我揣著相機(jī)與錄音谬运,去河邊找鬼隙赁。 笑死,一個(gè)胖子當(dāng)著我的面吹牛梆暖,可吹牛的內(nèi)容都是我干的伞访。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼轰驳,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼厚掷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起级解,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤冒黑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后勤哗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抡爹,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年芒划,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冬竟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡民逼,死狀恐怖诱咏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情缴挖,我是刑警寧澤袋狞,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站映屋,受9級(jí)特大地震影響苟鸯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜棚点,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一早处、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瘫析,春花似錦砌梆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至杖虾,卻和暖如春烂瘫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奇适。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工坟比, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留芦鳍,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓葛账,卻偏偏與公主長(zhǎng)得像柠衅,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子籍琳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355