基于MVP模式的 dagger-android 探索

近期接手了公司一個(gè)項(xiàng)目的重構(gòu)开伏,要基于MVPArms框架來(lái)做,而arms又是基于dagger2構(gòu)建;但是dagger2直接用于android的話用起來(lái)還是有些不太舒服茁影,仗著自己對(duì)dagger有些了解薪韩,花了些時(shí)間把a(bǔ)rms框架的dagger部分替換成了dagger-android确沸。重構(gòu)期間也遇到了一些問題捌锭,修修補(bǔ)補(bǔ)最后還算成功,對(duì)于dagger的理解也更深了一點(diǎn)罗捎;為了幫助自己記憶開始寫這篇文章观谦,同時(shí)也在這里分享給大家。

關(guān)于dagger2網(wǎng)上已經(jīng)有了不少優(yōu)秀的文章桨菜,我這里就直接從dagger-android開始講起了豁状,如果還對(duì)dagger2不太了解,建議先看看這個(gè)系列的文章Dagger2完全解析倒得,個(gè)人認(rèn)為非常不錯(cuò)泻红。

1. 一些概念

首先我們來(lái)回顧一下dagger三要素

  • 目標(biāo)類: 需要進(jìn)行依賴注入的類,即依賴于一些其他類實(shí)例的類霞掺。

  • module: 準(zhǔn)確地說(shuō)應(yīng)該是依賴谊路,用于為目標(biāo)類提供依賴。我們可以通過(guò)創(chuàng)建一個(gè)module手動(dòng)new對(duì)象對(duì)外提供依賴菩彬,也可以通過(guò)@inject注解類的構(gòu)造器讓dagger自動(dòng)創(chuàng)建對(duì)象提供依賴凶异。

  • commponent: 翻譯過(guò)來(lái)是組件的意思,在dagger中充當(dāng)ioc容器挤巡。我們知道component可以依賴一個(gè)或多個(gè)module剩彬,然后它一般還需要有一個(gè)inject方法,類似這樣:

    @Component(modules = {
            xxxModule.class,
            xxxModule.class
    })
    public interface AppComponent {
        void inject(App app);
    }
    

    那么它的作用就顯而易見了——component作為一個(gè)容器矿卑,封裝了它依賴的所有module提供的創(chuàng)建對(duì)象的方式喉恋。經(jīng)過(guò)dagger的編譯以后,我們?cè)谀繕?biāo)類調(diào)用component實(shí)現(xiàn)類的inject方法將它提供的依賴注入進(jìn)來(lái)母廷,之后就可以通過(guò)@inject注解從component里面拿到我們所需的對(duì)象了轻黑。

2. 如何構(gòu)建依賴關(guān)系

我們知道一個(gè)android項(xiàng)目必定有application,還可能有activity琴昆、fragment氓鄙、service...這些組件判哥,通常我們會(huì)在application(或者單例類)里面保存一些全局變量厨埋,以便在其他地方使用;而在activity中也可能需要暴露出共有變量給屬于它的fragments使用(比如在有多個(gè)fragment的tab頁(yè)面中)诫睬,這樣的話我們不得不通過(guò)get或者setArguments方法傳遞這些對(duì)象舷暮,非常地不優(yōu)雅态罪。下面我們來(lái)看看dagger的方式。

2.1 回顧dagger的構(gòu)建方式

現(xiàn)在我們從dagger的角度來(lái)看下面,我們可以把整個(gè)app看作一個(gè)根組件复颈,創(chuàng)建一個(gè)appComponent;activity看作它的子組件沥割,然后依次創(chuàng)建xxxActivityComponent耗啦,將它聲明為appComponent的子組件凿菩;

@Component(modules = {ActivityModule.class, ...})
public interface AppComponent {...}  

@Module(subcomponents = {MainComponent.class, ...})
public abstract class ActivityModule {...}  

@ActivityScope
@Subcomponent
public interface MainComponent {
    void inject(MainActivity activity);

    @Subcomponent.Builder
    interface Builder {
        @BindsInstance
        Builder view(MainContract.View view);

        MainComponent build();
    }
}  

然后在每個(gè)activity里面注入它自己的component

App.get(this)
    .getAppComponent()
    .mainComponentBuilder()
    .view(this)
    .build()
    .inject(this);

@BindsInstance: 由于項(xiàng)目用的是MVP模式,需要給presenter提供view實(shí)例帜讲,這里的view實(shí)際上就是activity蓄髓,它只能通過(guò)我們?cè)谧⑷氲臅r(shí)候傳入(我們無(wú)法實(shí)例化activity),而@BindsInstance注解的view方法就是把a(bǔ)ctivity作為view實(shí)例放到容器里了舒帮。

以上這些看起來(lái)似乎沒什么問題会喝,但是要知道我們一個(gè)項(xiàng)目里可能很多個(gè)activity,每個(gè)都需要這樣去注入的話是非常麻煩的玩郊,而且這種注入方式看起來(lái)并不是一目了然肢执。

下面我們來(lái)看看dagger.android的注入方式。

2.2 dagger.android的構(gòu)建方式

首先build.gradle中加入依賴包

implementation "com.google.dagger:dagger:$version_dagger2"
annotationProcessor "com.google.dagger:dagger-compiler:$version_dagger2"
implementation "com.google.dagger:dagger-android:$version_dagger2"
implementation "com.google.dagger:dagger-android-support:$version_dagger2"
annotationProcessor "com.google.dagger:dagger-android-processor:$version_dagger2"

接下來(lái)直接看看最終如何在目標(biāo)類中的注入依賴

AndroidInjection.inject(四大組件或者fragment)
AndroidSupportInjection.inject(v4包下的fragment)

注意译红,需要BroadcastReceiver中super.onReceive()之前調(diào)用预茄, fragment super.onAttach()之前,其他三大組件super.onCreate()之前調(diào)用侦厚。

如此簡(jiǎn)單耻陕!不再需要顯式地在目標(biāo)類中指明要注入哪個(gè)component,我們甚至能把它放到基類中就可以完成注入刨沦。這是怎么做到的呢诗宣?我們待會(huì)再來(lái)細(xì)說(shuō),再此之前我們還需要做一些別的事情想诅。

  1. AppComponent需要做一些調(diào)整

    @Component(modules = {
            AndroidInjectionModule.class,
            AndroidSupportInjectionModule.class,
            ActivityModule.class
    })
    public interface AppComponent {...}
    

    AndroidInjectionModule召庞, AndroidSupportInjectionModule分別是為了保證四大組件和fragment能夠被注入到容器中,后者是為了支持v4包下的fragment来破。

  2. 聲明activity對(duì)應(yīng)的子component方式需要改變

     @ActivityScope
     @Subcomponent(modules = {MainModule.class})
     public interface MainComponent extends AndroidInjector<MainActivity> {
    
         @Subcomponent.Builder
         abstract class Builder extends AndroidInjector.Builder<MainActivity> {}
     }  
    
     @Module
     public abstract class MainModule {
         @ActivityScope
         @Binds
         abstract MainContract.View provideView(MainActivity activity);
     }
    

    子component需要繼承AndroidInjector<四大組件或者fragment>接口篮灼,同時(shí)builder也需要繼承AndroidInjector.Builder<四大組件或者fragment>。AndroidInjector是干嗎用的徘禁?我們可以把它理解為注入器诅诱,有將commponent注入到目標(biāo)類能力的東西,但它只是一個(gè)接口送朱,具體的實(shí)現(xiàn)在子類(就是我們的component的實(shí)現(xiàn)類娘荡,由dagger編譯后生成,代碼位于build/source/apt/.../DaggerAppComponent.java)骤菠。

    你可能發(fā)現(xiàn)我們少了一些東西它改,我們并沒有像之前那樣把a(bǔ)ctivity作為MVP中的view傳入component,而是直接在module里面直接拿到了activity商乎,那么這個(gè)activity是從哪里來(lái)的呢?還記得AndroidInjection.inject(xxxActivity)嗎祭阀,當(dāng)我們?cè)诮oactivity注入component的時(shí)候鹉戚,同時(shí)也將activity本身傳入進(jìn)去了鲜戒,所以我們可以直接用它。

  3. 需要告訴dagger如何創(chuàng)建一個(gè)子component
    首先我們創(chuàng)建一個(gè)ActivityModule抹凳,用來(lái)管理所有activity對(duì)應(yīng)的component

     @Module(subcomponents = MainComponent.class)
     public abstract class ActivityModule {
         @Binds
         @IntoMap
         @ActivityKey(MainActivity.class)
         abstract AndroidInjector.Factory<? extends Activity>  
         bindMainActivity(MainComponent.Builder builder);
     }
    

    這段代碼實(shí)際上是告訴dagger MainActivity所對(duì)應(yīng)的component是哪一個(gè)遏餐,簡(jiǎn)單點(diǎn)說(shuō),就是將activity的具體類型作為key赢底,它對(duì)應(yīng)的component的創(chuàng)建方式(AndroidInjector.Factory<? extends Activity>失都,也就是component的工廠對(duì)象)作為值存到一個(gè)map里面,然后我們通過(guò)AndroidInjection.inject(xxxActivity)注入時(shí)幸冻,dagger就能通過(guò)傳入的類型去拿到對(duì)應(yīng)的工廠實(shí)例粹庞,創(chuàng)建component然后注入進(jìn)來(lái)。當(dāng)然洽损,如果我們需要注入的是其他組件庞溜,那么@ActivityKey就應(yīng)該換成對(duì)應(yīng)的xxxKey了。

  4. 在application里面注入根component

    public class App extends Application implements HasActivityInjector {
       @Inject
       DispatchingAndroidInjector<Activity> actInjector;
    
       @Override
       public void onCreate() {
           super.onCreate();
           DaggerAppComponent.builder()
                   .appModule(new AppModule(this))
                   .build()
                   .inject(this);
       }
    
       @Override
       public AndroidInjector<Activity> activityInjector() {
           return actInjector;
       }
    }
    

    如果我們要用dagger.android的方式在activity中注入依賴碑定,我們的application就需要實(shí)現(xiàn)HasActivityInjector接口流码,它只有一個(gè)抽象方法,需要返回一個(gè)AndroidInjector<Activity>的實(shí)例延刘,而AndroidInjector本身是一個(gè)接口漫试。這時(shí)候我們通過(guò)@inject注入一個(gè)DispatchingAndroidInjector<Activity>進(jìn)來(lái)就好了(如果需要用到其他組件或者fragment,也要實(shí)現(xiàn)對(duì)應(yīng)的HasXXXInjector接口)碘赖,最后別忘了注入根component商虐。

    那么這個(gè)DispatchingAndroidInjector有什么作用?它從哪里來(lái)到哪里去呢崖疤?我們來(lái)看一段它的源碼秘车。

    @Beta
    public final class DispatchingAndroidInjector<T> implements AndroidInjector<T> {
       ...
       private final Map<Class<? extends T>, Provider<AndroidInjector.Factory<? extends T>>>
           injectorFactories;
    
       @Inject
       DispatchingAndroidInjector(
           Map<Class<? extends T>, Provider<AndroidInjector.Factory<? extends T>>> injectorFactories) {
         this.injectorFactories = injectorFactories;
       }
    }
    

    到這里我們應(yīng)該能馬上明白了,它的構(gòu)造方法被@inject注解了劫哼,所以可以直接被注入叮趴。而它內(nèi)部保存了一個(gè)map,在構(gòu)造器中被注入賦值权烧。其實(shí)這個(gè)map就是之前我們?cè)谏弦还?jié)講過(guò)的眯亦,保存了每個(gè)activity(或其他組件)對(duì)應(yīng)的component的工廠實(shí)例。這個(gè)map又是從哪來(lái)的呢般码?答案就在AndroidInjectionModule里妻率,還記得嗎,我們?cè)贏ppComponent中安裝了它板祝,現(xiàn)在來(lái)看一看它的代碼宫静。

     @Beta
     @Module
     public abstract class AndroidInjectionModule {
       @Multibinds
       abstract Map<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>>
           activityInjectorFactories();
    
       @Multibinds
       abstract Map<Class<? extends Fragment>, AndroidInjector.Factory<? extends Fragment>>
           fragmentInjectorFactories();
           ......
     }
    

    一目了然,它直接對(duì)AppComponent提供了裝有各種component工廠實(shí)例的map。

    @Multibinds 這個(gè)注解需要結(jié)合之前創(chuàng)建的ActivityModule來(lái)看

    @Binds
    @IntoMap
    @ActivityKey(MainActivity.class)
    abstract AndroidInjector.Factory<? extends Activity>  
    bindMainActivity(MainComponent.Builder builder);
    

    @Binds 把builder轉(zhuǎn)化為它的父類AndroidInjector.Factory<T>孤里,然后@IntoMap 將它綁定到@Multibinds 注解的AndroidInjectionModule中提供Map<T, T>類型依賴的方法伏伯,這樣就根據(jù)<T>分類將每個(gè)子component的工廠實(shí)例放入一個(gè)Map<T, T>中,然后作為依賴提供出去捌袜。

3. 更優(yōu)雅的方式

寫了寫么多東西说搅,看起來(lái)dagger.adroid的方式好像并沒有好到哪里去,只是避免了在每個(gè)目標(biāo)類中寫一長(zhǎng)串的注入代碼虏等,但是別急弄唧,我們還有終極大招。
  先來(lái)看看最終代碼

@Module
public abstract class ActivityModule {
    @ActivityScope
    @ContributesAndroidInjector(modules = MainModule.class)
    abstract MainActivity provideMainActivity();
}

ActivityModule直接簡(jiǎn)化成了這個(gè)樣子霍衫,而且我們不再需要MainComponent(不再需要顯式地創(chuàng)建子Component)候引,子component依賴的module現(xiàn)在直接聲明在@ContributesAndroidInjector里面就好了。

@ContributesAndroidInjector 做了什么呢慕淡?其實(shí)一切并沒有變背伴,它只是隱式地幫我們創(chuàng)建了一個(gè)子component,看看編譯后的代碼build/source/apt/.../ActivityModule_ProvideMainActivity

@Module(
  subcomponents = ActivityModule_ProvideMainActivity.MainActivitySubcomponent.class
)
@Generated("dagger.android.processor.AndroidProcessor")
public abstract class ActivityModule_ProvideMainActivity {
  private ActivityModule_ProvideMainActivity() {}

  @Binds
  @IntoMap
  @ActivityKey(MainActivity.class)
  abstract AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory(
      MainActivitySubcomponent.Builder builder);

  @Subcomponent(modules = MainModule.class)
  @ActivityScope
  public interface MainActivitySubcomponent extends AndroidInjector<MainActivity> {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<MainActivity> {}
  }
}

看吧峰髓,一切并沒有變傻寂。

4. 從源碼理清思路

知其然不知其所以然往往容易犯錯(cuò),上一部分的結(jié)尾我們分析了DispatchingAndroidInjector的一些東西携兵,現(xiàn)在我們來(lái)跟著源碼從頭理一理思路疾掰。
  還是從AndroidInjection.inject(xxx)開始,我們點(diǎn)進(jìn)源碼

public static void inject(Activity activity) {
   checkNotNull(activity, "activity");
   Application application = activity.getApplication();
   if (!(application instanceof HasActivityInjector)) {
     throw new RuntimeException(
         String.format(
             "%s does not implement %s",
             application.getClass().getCanonicalName(),
             HasActivityInjector.class.getCanonicalName()));
   }

   AndroidInjector<Activity> activityInjector =
       ((HasActivityInjector) application).activityInjector();
   checkNotNull(activityInjector, "%s.activityInjector() returned null", application.getClass());

   activityInjector.inject(activity);
 }

很簡(jiǎn)單徐紧,判斷application是否實(shí)現(xiàn)了HasActivityInjector接口静檬,然后調(diào)用application的activityInjector函數(shù)拿到AndroidInjector實(shí)例(正是我們之前在applicaton中@inject進(jìn)去的DispatchingAndroidInjector),最后調(diào)用了DispatchingAndroidInjector的inject方法并级,我們接著往下面看拂檩,回到DispatchingAndroidInjector

@Beta
public final class DispatchingAndroidInjector<T> implements AndroidInjector<T> {
  ......
  @Override
  public void inject(T instance) {
    boolean wasInjected = maybeInject(instance);
    if (!wasInjected) {
      throw new IllegalArgumentException(errorMessageSuggestions(instance));
    }
  }  

  @CanIgnoreReturnValue
  public boolean maybeInject(T instance) {
    Provider<AndroidInjector.Factory<? extends T>> factoryProvider =
        injectorFactories.get(instance.getClass());
    if (factoryProvider == null) {
      return false;
    }

    @SuppressWarnings("unchecked")
    AndroidInjector.Factory<T> factory = (AndroidInjector.Factory<T>) factoryProvider.get();
    try {
      AndroidInjector<T> injector =
          checkNotNull(
              factory.create(instance), "%s.create(I) should not return null.", factory.getClass());

      injector.inject(instance);
      return true;
    } catch (ClassCastException e) {
      throw new InvalidInjectorBindingException(
          String.format(
              "%s does not implement AndroidInjector.Factory<%s>",
              factory.getClass().getCanonicalName(), instance.getClass().getCanonicalName()),
          e);
    }
  }
}

我們直接看最終調(diào)用的maybeInject(),它根據(jù)我們傳入的目標(biāo)類的class從map中拿到對(duì)應(yīng)的component(我們的子component全部實(shí)現(xiàn)了AndroidInjector接口嘲碧,所以這里的injector就是component)的工廠實(shí)例稻励,然后創(chuàng)建了component,最后調(diào)用它的inject方法將依賴注入到目標(biāo)類的實(shí)例里面愈涩。具體的注入過(guò)程可以在dagger為我們生成的xxxComponentImpl里面看到望抽,它是DaggerAppComponent的內(nèi)部類。

現(xiàn)在來(lái)總結(jié)一下履婉,首先AndroidInjector接口只有一個(gè)inject抽象方法煤篙,我們的子component和DispatchingAndroidInjector都是它的子類,當(dāng)通過(guò)AndroidInjection.inject(xxx)注入的時(shí)候毁腿,實(shí)際上是調(diào)用application里的DispatchingAndroidInjector的inject方法辑奈,而它本身并不做實(shí)際的注入苛茂,只是起了一個(gè)分發(fā)的作用,最后找到并調(diào)用了當(dāng)前子component(injecttor)的inject方法進(jìn)行實(shí)際的依賴注入身害。

5. 結(jié)合實(shí)例

demo地址:https://github.com/ColorfulHorse/MVPDemo

demo很簡(jiǎn)單味悄,主要就是一個(gè)mainActivity通過(guò)viewPager管理了三個(gè)fragment草戈,weeklyFragment里面請(qǐng)求了一個(gè)七天的天氣接口塌鸯,列表展示了出來(lái),通過(guò)數(shù)據(jù)庫(kù)做了本地緩存唐片。
看看AppComponent

@Singleton
@Component(modules = {
        AndroidInjectionModule.class,
        AppModule.class,
        OkhttpModule.class,
        RetrofitModule.class,
        ApiServiceModule.class,
        DBModule.class,
        ActivityModule.class})
public interface AppComponent {
    void inject(App app);

    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder application(Application application);
        AppComponent build();
    }
}

依賴了若干module丙猬,分別提供okhttpClient實(shí)例,retrofit實(shí)例费韭,retrofitService實(shí)例茧球,數(shù)據(jù)庫(kù)實(shí)例;這里數(shù)據(jù)庫(kù)用的是ObjectBox庫(kù)星持,有興趣的可以了解一下抢埋。
其實(shí)也不需要?jiǎng)?chuàng)建這么多module,也可以全部放到一個(gè)appModule里面就可以督暂,我這里只是做了一個(gè)分類揪垄,具體情況視項(xiàng)目復(fù)雜度而定。

再看看AcrivityModule

@Module
public abstract class ActivityModule {

    @ActivityScope
    @ContributesAndroidInjector(modules = {
            MainModule.class,
            MainFragmentModule.class
    })
    abstract MainActivity provideMainActivity();

    @ContributesAndroidInjector
    @ActivityScope
    abstract ForecastActivity provideForecastActivity();
}

管理了一個(gè)列表activity和一個(gè)詳情activity逻翁, MainActivity有一個(gè)MainFragmentModule管理其下的三個(gè)fragment

@Module
public abstract class MainFragmentModule {

    @FragmentScope
    @ContributesAndroidInjector
    abstract DailyFragment provideDailyFragment();

    @FragmentScope
    @ContributesAndroidInjector(modules = WeeklyModule.class)
    abstract WeeklyFragment provideWeeklyFragment();

    @FragmentScope
    @ContributesAndroidInjector
    abstract MonthlyFragment provideMonthlyFragment();

}

這樣看起來(lái)整個(gè)結(jié)構(gòu)就比較明朗饥努,依賴關(guān)系層次明顯,appComponent為根組件八回,其下activityComponent為子組件酷愧,再下面還有fragment對(duì)應(yīng)的子組件。當(dāng)然這一切只是一個(gè)簡(jiǎn)單的示例缠诅,也許還有更好的方式等你探索溶浴。

本文到這里也就結(jié)束了,更多的東西demo里面都寫得比較完整管引,就不再細(xì)講士败。
如有不足之處歡迎指出。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末汉匙,一起剝皮案震驚了整個(gè)濱河市拱烁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌噩翠,老刑警劉巖戏自,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異伤锚,居然都是意外死亡擅笔,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)猛们,“玉大人念脯,你說(shuō)我怎么就攤上這事⊥涮裕” “怎么了绿店?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)庐橙。 經(jīng)常有香客問我假勿,道長(zhǎng),這世上最難降的妖魔是什么态鳖? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任转培,我火速辦了婚禮,結(jié)果婚禮上浆竭,老公的妹妹穿的比我還像新娘浸须。我一直安慰自己,他們只是感情好邦泄,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布删窒。 她就那樣靜靜地躺著,像睡著了一般虎韵。 火紅的嫁衣襯著肌膚如雪易稠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天包蓝,我揣著相機(jī)與錄音驶社,去河邊找鬼。 笑死测萎,一個(gè)胖子當(dāng)著我的面吹牛亡电,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播硅瞧,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼份乒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了腕唧?” 一聲冷哼從身側(cè)響起或辖,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎枣接,沒想到半個(gè)月后颂暇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡但惶,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年耳鸯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了湿蛔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡县爬,死狀恐怖阳啥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情财喳,我是刑警寧澤察迟,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站纲缓,受9級(jí)特大地震影響卷拘,放射性物質(zhì)發(fā)生泄漏喊废。R本人自食惡果不足惜祝高,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望污筷。 院中可真熱鬧工闺,春花似錦、人聲如沸瓣蛀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)惋增。三九已至叠殷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間诈皿,已是汗流浹背林束。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留稽亏,地道東北人壶冒。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像截歉,于是被迫代替她去往敵國(guó)和親胖腾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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