Fragment(四)常見(jiàn)問(wèn)題

Fragment(四)常見(jiàn)問(wèn)題

博客對(duì)應(yīng)的Demo地址:GitHubGitee

通過(guò)這篇博客犁珠,我們能知道以下問(wèn)題:

  • Fragment 在不同情況下實(shí)現(xiàn)網(wǎng)絡(luò)延遲
  • Fragment 為什么一定要有無(wú)參構(gòu)造材诽?
  • FragmentActivity 傳遞數(shù)據(jù)方式
  • 嵌套 Fragment 時(shí)父 Fragment 生命周期傳遞到子 Fragment 中的方式

1. Fragment 在不同情況下實(shí)現(xiàn)網(wǎng)絡(luò)延遲

其實(shí)使用延遲加載主要目的是在頁(yè)面對(duì)用戶可見(jiàn)時(shí)在加載網(wǎng)絡(luò),避免資源浪費(fèi)寿烟,那么這個(gè)問(wèn)題就轉(zhuǎn)換成了 Fragment 在不同情況下怎樣判斷對(duì)用戶的可見(jiàn)性,這個(gè)問(wèn)題在前面的幾篇博客中都或多或少的提到了辛燥,這里直接做一個(gè)總結(jié):

  1. add()+show()/hide():生命周期方法不對(duì)筛武,多個(gè)添加的 Fragment 一開(kāi)始就會(huì)會(huì)同時(shí)執(zhí)行到 onResume(),退出時(shí)又會(huì)同時(shí)執(zhí)行其他生命周期方法(onPause()onDetach())挎塌,所以不能直接通過(guò)生命周期方法處理徘六,而是需要通過(guò) onHiddenChanged(boolean hidden) 方法判斷。

  2. replace():“替換”榴都,這種方式會(huì)銷(xiāo)毀布局容器內(nèi)的已有 Fragment待锈,然后重新創(chuàng)建一個(gè)新的 Fragment嘴高,銷(xiāo)毀的Fragment執(zhí)行onPause()onDetach()回調(diào)方法竿音,新的 Fragment 會(huì)執(zhí)行 onAttach()onResume() 回調(diào)谍失,所以直接在 onStart()onResume() 回調(diào)中處理就行了。

  3. ViewPager:在AndroidX之前只有一種情況莹汤,在AndroidX中有兩種情況快鱼,在Adapter構(gòu)造中增加了一個(gè) behavior 參數(shù)(取值:BEHAVIOR_SET_USER_VISIBLE_HINTBEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)纲岭,非AndroidX就相當(dāng)于取值 BEHAVIOR_SET_USER_VISIBLE_HINT抹竹,所以兩種情況需要分別來(lái)看:

    • BEHAVIOR_SET_USER_VISIBLE_HINT:生命周期方法監(jiān)聽(tīng)不準(zhǔn)確,需要通過(guò) setUserVisibleHint() 方法來(lái)監(jiān)聽(tīng)止潮,當(dāng)方法傳入值為true的時(shí)候窃判,說(shuō)明Fragment可見(jiàn),為false的時(shí)候說(shuō)明Fragment被切走了喇闸。但是需要注意的是袄琳,這個(gè)方法不屬于生命周期方法询件,所以它可能在生命周期方法執(zhí)行之前就執(zhí)行了,也就是說(shuō)唆樊,有可能執(zhí)行這個(gè)方法的時(shí)候宛琅,Fragment 還沒(méi)有被添加到容器中,所以需要進(jìn)行判斷一下逗旁。

    • BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT:生命周期方法是正常的嘿辟,只有正在顯示的 Fragment 執(zhí)行到 onResume() 方法,其他 Fragment 只會(huì)執(zhí)行到 onStart() 方法片效,并且當(dāng) Fragment 切換到顯示時(shí)執(zhí)行 onResume() 方法红伦,切換到不顯示狀態(tài)時(shí)觸發(fā) onPause() 方法。

  4. ViewPager2:生命周期方法也是正常的淀衣,只有正在顯示的 Fragment 執(zhí)行到 onResume() 方法昙读,其他 Fragment 只會(huì)執(zhí)行到 onStart() 方法,并且當(dāng) Fragment 切換到顯示時(shí)執(zhí)行 onResume() 方法膨桥,切換到不顯示狀態(tài)時(shí)觸發(fā) onPause() 方法箕戳。

2. Fragment 為什么一定要有無(wú)參構(gòu)造?

正常情況下国撵,我們?nèi)绻褂糜袇?gòu)造,自己在創(chuàng)建 Fragment 對(duì)象使用時(shí)玻墅,也是沒(méi)問(wèn)題的介牙,但是如果 FragmentActivity 銷(xiāo)毀自動(dòng)重建,恢復(fù)頁(yè)面狀態(tài)時(shí)澳厢,如果頁(yè)面包含 Fragment环础,那么沒(méi)有無(wú)參構(gòu)造就會(huì)發(fā)送異常,我們從源碼里來(lái)看一下剩拢。

  • FragmentActivity 初始化方法

      public FragmentActivity() {
          super();
          init();
      }
      @ContentView
      public FragmentActivity(@LayoutRes int contentLayoutId) {
          super(contentLayoutId);
          init();
      }
    
      private void init() {
          // 增加 Context 可用監(jiān)聽(tīng)
          addOnContextAvailableListener(new OnContextAvailableListener() {
              @Override
              public void onContextAvailable(@NonNull Context context) {
                  mFragments.attachHost(null /*parent*/);
                  Bundle savedInstanceState = getSavedStateRegistry()
                          .consumeRestoredStateForKey(FRAGMENTS_TAG);
    
                  // 如果 savedInstanceState 不為null线得,恢復(fù)頁(yè)面狀態(tài)
                  if (savedInstanceState != null) {
                      Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
                      // 調(diào)用 FragmentController#restoreSaveState() 方法
                      mFragments.restoreSaveState(p);
                  }
              }
          });
      }
    

    當(dāng)FragmentActivity恢復(fù)頁(yè)面狀態(tài)是,會(huì)調(diào)用 FragmentController#restoreSaveState() 方法

      public void restoreSaveState(@Nullable Parcelable state) {
          mHost.mFragmentManager.restoreSaveState(state);
      }
    

    調(diào)用 FragmentManager#restoreSaveState() 方法

      void restoreSaveState(@Nullable Parcelable state) {
          fragmentStateManager = new FragmentStateManager(mLifecycleCallbacksDispatcher,
                              mFragmentStore, mHost.getContext().getClassLoader(),
                              getFragmentFactory(), fs);
      }
    
      // 獲取 FragmentFactory 對(duì)象
      public FragmentFactory getFragmentFactory() {
          if (mFragmentFactory != null) {
              return mFragmentFactory;
          }
          if (mParent != null) {
              return mParent.mFragmentManager.getFragmentFactory();
          }
          return mHostFragmentFactory;
      }
    
      // FragmentFactory 對(duì)象初始化過(guò)程
      private FragmentFactory mHostFragmentFactory = new FragmentFactory() {
          @Override
          public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) {
              // 回調(diào)中調(diào)用 FragmentContainer#instantiate() 方法 
              return getHost().instantiate(getHost().getContext(), className, null);
          }
      };
    

    FragmentContainer#instantiate() 方法

      public Fragment instantiate(@NonNull Context context, @NonNull String className,
              @Nullable Bundle arguments) {
          return Fragment.instantiate(context, className, arguments);
      }
    

    繼續(xù)查看 Fragment#instantiate() 方法

      public static Fragment instantiate(@NonNull Context context, @NonNull String fname,
              @Nullable Bundle args) {
          try {
              Class<? extends Fragment> clazz = FragmentFactory.loadFragmentClass(
                      context.getClassLoader(), fname);
              Fragment f = clazz.getConstructor().newInstance();
              if (args != null) {
                  args.setClassLoader(f.getClass().getClassLoader());
                  f.setArguments(args);
              }
              return f;
          } catch (Exception e) {
          }
      }
    

    通過(guò)反射創(chuàng)建實(shí)例徐伐,并且調(diào)用的是無(wú)參構(gòu)造贯钩,所以為了避免異常產(chǎn)生,我們需要給 Fragment 定義無(wú)參構(gòu)造办素。

通過(guò)上面的分析角雷,我們知道了,雖然不給 Fragment 提供無(wú)參構(gòu)造性穿,正常情況下也能使用勺三,但是一旦 Fragment 容器異常重建,恢復(fù)狀態(tài)時(shí)需曾,那么就會(huì)拋出異常吗坚,導(dǎo)致崩潰祈远,所以我們一定需要給 Fragment 提供無(wú)參構(gòu)造,推薦用法商源,Fragment 不適用帶參構(gòu)造车份,參數(shù)是通過(guò) Fragment#setArguments() 方法傳遞。

3. FragmentActivity 傳遞數(shù)據(jù)方式

在使用 FragmentActivity 的過(guò)程當(dāng)中炊汹,不免需要進(jìn)行數(shù)據(jù)傳遞躬充,那么他們有哪些方式可以傳遞了。當(dāng)然這里所討論的方式讨便,不包括Android原生的廣播充甚、文件、內(nèi)容提供者霸褒、數(shù)據(jù)庫(kù)等形式伴找,也不包括第三方的 EventBus、RxBus 等全局通知形式废菱,而是僅內(nèi)存中他們相互傳遞的方式技矮。

ActivityFragment 傳遞數(shù)據(jù)

首先我們看一下ActivityFragment 傳遞數(shù)據(jù)的方式,一般有四種形式:構(gòu)造方法殊轴、Fragment#setArguments() 方法衰倦、自定義Fragment實(shí)例方法和接口方式,我們來(lái)分別看一下

  • 1. 構(gòu)造方法
    這種方法不說(shuō)了旁理,一是比較簡(jiǎn)單樊零,二是不推薦使用帶參構(gòu)造創(chuàng)建 Fragment,原因在上面已經(jīng)說(shuō)過(guò)了孽文,就不再重復(fù)驻襟。

  • 2. Fragment#setArguments()
    這是 Fragment 自帶的方法,通過(guò) Fragment 實(shí)例調(diào)用 setArguments() 方法芋哭,可以傳遞一系列數(shù)據(jù)給 Fragment沉衣,Fragment 通過(guò) getArguments() 方法獲取。

      // 傳遞數(shù)據(jù)
      fun newInstance(content: String, color: Int): Vp2Fragment {
          val arguments = Bundle()
          arguments.putString("content", content)
          arguments.putInt("color", color)
          arguments.putString("tag", content)
          val vpFragment = Vp2Fragment()
          vpFragment.arguments = arguments
          return vpFragment
      }
    
      // 獲取數(shù)據(jù)
      arguments?.apply {
          var content = getString("content")
          var tag = getString("tag")
          var color = getInt("color")
      }
    
  • 3. 自定義Fragment實(shí)例方法
    這種方式和 getArguments() 方法類似减牺,我們?cè)?Fragment 自定義方法豌习,然后再 Activity 中獲取Fragment對(duì)象,然后調(diào)用其方法烹植,傳遞數(shù)據(jù)給 Fragment斑鸦。

  • 4. 接口方式
    定義一個(gè)接口,在需要傳遞數(shù)據(jù)的各個(gè) Fragment 中實(shí)現(xiàn)接口草雕,然后在注冊(cè)到宿主 Activity 中巷屿,當(dāng) Activity 數(shù)據(jù)中發(fā)送改變時(shí),調(diào)用接口方法墩虹,將數(shù)據(jù)傳遞到實(shí)現(xiàn)接口的 Fragment 中嘱巾。

    接口定義:

      // 定義接口
      interface ActivityDataChangeListener {
          fun onDataChange(message: String)
      }
    

    Activity 中相關(guān)方法:

      // Activity中保存接口和增加注冊(cè)方法
      private val listenerList = ArrayList<ActivityDataChangeListener>()
    
      /**
       * 注冊(cè)監(jiān)聽(tīng)
       */
      open fun registerListener(dataChangeListener: ActivityDataChangeListener) {
          listenerList.add(dataChangeListener)
      }
    
      /**
       * 移除監(jiān)聽(tīng)
       */
      open fun unRegisterListener(dataChangeListener: ActivityDataChangeListener) {
          listenerList.remove(dataChangeListener)
      }
    
      // Activity數(shù)據(jù)改變時(shí)憨琳,回調(diào)接口方法
      titleView.titleContentView.setOnClickListener {
          for (dataChangeListener in listenerList) {
              dataChangeListener.onDataChange("currentItem: " + viewPager.currentItem)
          }
      }
    

    Fragment 相關(guān)方法

      // 初始化監(jiān)聽(tīng)
      private var dataChangeListener = object : ActivityDataChangeListener {
          override fun onDataChange(message: String) {
              Logger.i("ActivityDataChangeListener: $message")
          }
      }
    
      // 頁(yè)面創(chuàng)建時(shí)注冊(cè)監(jiān)聽(tīng)到 Activity 中
      override fun onCreateView(
          inflater: LayoutInflater,
          container: ViewGroup?,
          savedInstanceState: Bundle?
      ): View? {
          (activity as VpFragmentActivity).registerListener(dataChangeListener)
          return super.onCreateView(inflater, container, savedInstanceState)
      }
    
      // 頁(yè)面銷(xiāo)毀時(shí)從 Activity 中移除監(jiān)聽(tīng)
      override fun onDestroyView() {
          super.onDestroyView()
          (activity as VpFragmentActivity).unRegisterListener(dataChangeListener)
      }
    

    以上就是通過(guò)接口的方式,由 ActivityFragment 傳遞數(shù)據(jù)的主要代碼旬昭。

FragmentActivity 傳遞數(shù)據(jù)

FragmentActivity 傳遞數(shù)據(jù)的方式篙螟,一般有兩種形式:調(diào)用Activity中的方法和接口方式,我們來(lái)分別看一下:

  • 1. 調(diào)用Activity中的方法
    這種方式就是直接在 Activity 中定義方法问拘,然后在 Fragment 中通過(guò)獲取 getActivity() 然后強(qiáng)轉(zhuǎn)遍略,在調(diào)用方法。

    Activity 中定義方法

      open fun updateActivityData(message: String) {
          Logger.i("Activity data update: $message")
      }
    

    Fragment 中獲取 Activity 后強(qiáng)轉(zhuǎn)在調(diào)用方法骤坐,傳遞數(shù)據(jù)到 Activity绪杏。

      (activity as Vp2FragmentActivity).updateActivityData("新數(shù)據(jù)")
    
  • 2. 接口方式
    定義一個(gè)接口,宿主 Activity 實(shí)現(xiàn)接口纽绍,當(dāng) Fragment 數(shù)據(jù)中發(fā)送改變時(shí)蕾久,調(diào)用接口方法,將數(shù)據(jù)傳遞到實(shí)現(xiàn)接口的 Activity 中拌夏。

    接口定義:

      // 定義接口
      interface FragmentDataChangeListener {
          fun onDataChange(message: String)
      }
    

    Activity 中相關(guān)方法:

      // Activity中實(shí)現(xiàn)接口 FragmentDataChangeListener
      class Vp2FragmentActivity : BaseActivity(), FragmentDataChangeListener {
          // 重寫(xiě)方法
          override fun onDataChange(message: String) {
              Logger.i("FragmentDataChangeListener: $message")
          }
      }
    

    Fragment 相關(guān)方法

      private lateinit var dataChangeListener: FragmentDataChangeListener
    
      override fun onAttach(context: Context) {
          super.onAttach(context)
          // 將宿主Activity強(qiáng)轉(zhuǎn)成接口對(duì)象
          dataChangeListener = activity as FragmentDataChangeListener
      }
    
      // 更新數(shù)據(jù)時(shí)僧著,調(diào)用接口方法,Activity中就會(huì)收到新的數(shù)據(jù)
      tvContent.setOnClickListener {
          dataChangeListener.onDataChange("Fragment 新數(shù)據(jù)")
      }
    

    以上就是通過(guò)接口的方式障簿,由 FragmentActivity 傳遞數(shù)據(jù)的主要代碼盹愚。

擴(kuò)展: FragmentFragment 之間傳遞數(shù)據(jù)

如果兩個(gè) Fragment 是父子關(guān)系的話,那么與 ActivityFragment 之間傳遞數(shù)據(jù)方式一樣站故;如果兩個(gè) Fragment 是兄弟關(guān)系的話(都是在同一個(gè) ActivityFragment 中)杯拐,那么他們之間需要相互傳遞數(shù)據(jù)的話,就需要通過(guò)宿主進(jìn)行中轉(zhuǎn)了世蔗,先將數(shù)據(jù)傳遞向上給宿主 ActivityFragment 中,然后在向下傳遞給另一個(gè) Fragment朗兵,傳遞方式還是和上面一樣污淋。

4. 嵌套 Fragment 時(shí)父 Fragment 生命周期傳遞到子 Fragment 中的方式

正常情況下宿主 Fragment 在生命周期執(zhí)行的時(shí)候會(huì)相應(yīng)的分發(fā)到子 Fragment 中,但是 setUserVisibleHint()onHiddenChanged() 卻沒(méi)有進(jìn)行相應(yīng)的回調(diào)余掖。試想一下寸爆,一個(gè) ViewPager 中有一個(gè) FragmentA 的tab,而 FragmentA 中有一個(gè)子FragmentB盐欺,FragmentA 被滑走了赁豆,FragmentB 并不能接收到 setUserVisibleHint() 事件,onHiddenChange() 事件也是一樣的冗美,那么肯定是我們不希望看到的魔种,那么有什么辦法能夠避免這種問(wèn)題了。一般有兩種方式解決這個(gè)問(wèn)題:

  1. 宿主 Fragment 提供可見(jiàn)性的回調(diào)粉洼,子 Fragment 監(jiān)聽(tīng)改回調(diào)节预,有點(diǎn)類似于觀察者模式
  2. 宿主 Fragment 可見(jiàn)性變化的時(shí)候叶摄,主動(dòng)去遍歷所有的 子 Fragment,調(diào)用 子 Fragment 的相應(yīng)方法

1.宿主 Fragment 提供可見(jiàn)性的回調(diào)安拟,子 Fragment 監(jiān)聽(tīng)改回調(diào)

第一步蛤吓,先定義一個(gè)接口

interface OnFragmentVisibilityChangedListener {
    fun onFragmentVisibilityChanged(visible: Boolean)
}

第二步,在 ParentFragment 中提供 addOnVisibilityChangedListener()removeOnVisibilityChangedListener() 方法糠赦,這里需要注意的是会傲,我們需要用一個(gè) ArrayList 來(lái)保存所有的 listener,因?yàn)橐粋€(gè)宿主 Fragment 可能有多個(gè)子 Fragment拙泽。

當(dāng) Fragment 可見(jiàn)性變化的時(shí)候淌山,會(huì)遍歷 List 調(diào)用 OnFragmentVisibilityChangedListeneronFragmentVisibilityChanged() 方法

class ParentFragment : Fragment() {
    private val listeners = ArrayList<OnFragmentVisibilityChangedListener>()

    fun addOnVisibilityChangedListener(listener: OnFragmentVisibilityChangedListener?) {
        listener?.apply {
            listeners.add(this)
        }
    }

    fun removeOnVisibilityChangedListener(listener: OnFragmentVisibilityChangedListener?) {
        listener?.apply {
            listeners.remove(this)
        }
    }

    override fun onHiddenChanged(hidden: Boolean) {
        super.onHiddenChanged(hidden)
        for (listener in listeners) {
            listener.onFragmentVisibilityChanged(!hidden)
        }
    }

    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
        for (listener in listeners) {
            listener.onFragmentVisibilityChanged(isVisibleToUser)
        }
    }
}

第三步,在 Fragment#attach() 的時(shí)候奔滑,我們通過(guò) getParentFragment() 方法艾岂,拿到宿主 Fragment,進(jìn)行監(jiān)聽(tīng)朋其。這樣王浴,當(dāng)宿主 Fragment 可見(jiàn)性變化的時(shí)候,子 Fragment 能感應(yīng)到梅猿。

class ChildFragment : Fragment(), OnFragmentVisibilityChangedListener {
    override fun onAttach(context: Context) {
        super.onAttach(context)
        if (parentFragment is ParentFragment) {
            (parentFragment as ParentFragment).addOnVisibilityChangedListener(this)
        }
    }
    override fun onFragmentVisibilityChanged(visible: Boolean) {
        // 可見(jiàn)性發(fā)送改變
    }

    override fun onDetach() {
        super.onDetach()
        if (parentFragment is ParentFragment) {
            (parentFragment as ParentFragment).removeOnVisibilityChangedListener(this)
        }
    }
}

2. 宿主 Fragment 可見(jiàn)性變化的時(shí)候氓辣,主動(dòng)去遍歷所有的 子 Fragment

第一步,與第一種方式一樣袱蚓,先定義一個(gè)接口

interface OnFragmentVisibilityChangedListener {
    fun onFragmentVisibilityChanged(visible: Boolean)
}

第二步钞啸,子 Fragment 實(shí)現(xiàn)接口

class ChildFragment : Fragment(), OnFragmentVisibilityChangedListener {
    override fun onFragmentVisibilityChanged(visible: Boolean) {
        // 可見(jiàn)性發(fā)送改變
    }
}

第三步,宿主 Fragment 生命周期發(fā)生變化的時(shí)候喇潘,遍歷子 Fragment体斩,調(diào)用相應(yīng)的方法,通知生命周期發(fā)生變化

class ParentFragment : Fragment() {
    override fun onHiddenChanged(hidden: Boolean) {
        super.onHiddenChanged(hidden)
        onFragmentVisibilityChanged(!hidden)
    }

    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
        onFragmentVisibilityChanged(isVisibleToUser)
    }

    private fun onFragmentVisibilityChanged(visible: Boolean) {
        var fragments = childFragmentManager.fragments
        if (fragments.isEmpty()) return
        for (fragment in fragments) {
            if (fragment is OnFragmentVisibilityChangedListener) {
                fragment.onFragmentVisibilityChanged(visible)
            }
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末颖低,一起剝皮案震驚了整個(gè)濱河市絮吵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌忱屑,老刑警劉巖蹬敲,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異莺戒,居然都是意外死亡伴嗡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)从铲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)瘪校,“玉大人,你說(shuō)我怎么就攤上這事名段≡伲” “怎么了赏寇?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)价认。 經(jīng)常有香客問(wèn)我嗅定,道長(zhǎng),這世上最難降的妖魔是什么用踩? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任渠退,我火速辦了婚禮,結(jié)果婚禮上脐彩,老公的妹妹穿的比我還像新娘碎乃。我一直安慰自己,他們只是感情好惠奸,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布梅誓。 她就那樣靜靜地躺著,像睡著了一般佛南。 火紅的嫁衣襯著肌膚如雪梗掰。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天嗅回,我揣著相機(jī)與錄音及穗,去河邊找鬼。 笑死绵载,一個(gè)胖子當(dāng)著我的面吹牛埂陆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播娃豹,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼焚虱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了懂版?” 一聲冷哼從身側(cè)響起著摔,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎定续,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體禾锤,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡私股,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了恩掷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片倡鲸。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖黄娘,靈堂內(nèi)的尸體忽然破棺而出峭状,到底是詐尸還是另有隱情克滴,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布优床,位于F島的核電站劝赔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏胆敞。R本人自食惡果不足惜着帽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望移层。 院中可真熱鬧仍翰,春花似錦、人聲如沸观话。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)频蛔。三九已至灵迫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間帽驯,已是汗流浹背龟再。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留尼变,地道東北人利凑。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像嫌术,于是被迫代替她去往敵國(guó)和親哀澈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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