使用Dagger 2为Android MVP设置模块和组件 - 具有多个片段的活动

时间:2017-06-18 14:27:00

标签: android mvp dagger-2 dagger

我和Dagger 2合作已经有一段时间了,我还在努力解决一些问题。有一件事我还是管理得很好 正在为不同情况设置模块和组件,例如具有多个片段的活动。 我见过很多实现,大部分时间都有点不同。

所以,让我公开一下使用MVP的当前应用程序结构,如果我的实现没有问题,我想要一些意见。

@Module
public final class ApplicationModule {

private Context mContext;


public ApplicationModule(Context context){
    mContext = context;
}


public ApplicationModule(){
    mContext = null;
}

@Provides
Context provideContext(){
    return mContext;
}

@Singleton
@Provides
public SharedPreferences getAppPreferences(){
    return mContext.getSharedPreferences("CalorieApp",Context.MODE_PRIVATE);
 }
}

@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {

void inject(MainApplication mainApplication);

SharedPreferences sharedPreferences();

}

在这个AppModule中,我通常只设置我的应用程序需要的Singleton。像SharedPreferences或任何与网络请求相关的内容。 这个模块和组件在某种程度上是标准的,我总是以这样的方式创建它们来启动我的应用程序。

然后我为Activity设置了我的模块和组件,它将在ApplicationComponent上具有依赖性

@Module
public class ActivityModule {

private Activity activity;

public ActivityModule(Activity activity){
    this.activity = activity;
}

@Provides
Activity provideActivity(){
    return  activity;
 }
}

@PerActivity
@Component(dependencies = ApplicationComponent.class, modules = 
  ActivityModule.class)
public interface ActivityComponent {

void inject(WelcomeActivity welcomeActivity);

void inject(MainActivity mainActivity);
}

现在,MainActivity有3个片段,我将为片段和1个组件创建3个模块

@Module
public class HomeFragmentModule {

private HomeFragmentContract.View mView;

public HomeFragmentModule(HomeFragmentContract.View view){
    mView = view;
}

@Provides
HomeFragmentContract.View provideHomeFragmentView(){
    return mView;
  }

}

@Module
public class ChartsFragmentModule {

private ChartsFragmentContract.View mView;

public ChartsFragmentModule(ChartsFragmentContract.View view){
    mView = view;
}

@Provides
ChartsFragmentContract.View provideChartsFragmentView(){
    return mView;
}
}

@Module
public class ProfileFragmentModule {

private ProfileFragmentContract.View mView;

public ProfileFragmentModule(ProfileFragmentContract.View view){
    mView = view;
}

@Provides
ProfileFragmentContract.View provideProfileFragmentContract(){
    return mView;
}

}

@PerFragment
@Component(dependencies = ActivityComponent.class ,
    modules = {ChartsFragmentModule.class, HomeFragmentModule.class, 
ProfileFragmentModule.class})
public interface FragmentComponent {

void inject(ChartsFragment chartsFragment);

void inject(HomeFragment homeFragment);

void inject(ProfileFragment profileFragment);
}

然后我将必须首先在我的应用程序类中实例化Dagger,然后在每个活动和片段中实例化

applicationComponent = DaggerApplicationComponent.builder()
            .applicationModule(new ApplicationModule(this))
            .build();

例如,在WelcomeActivity中,我将它实例化为:

    DaggerActivityComponent.builder()
            .activityModule(new ActivityModule(this))
            .applicationComponent(((MainApplication) 
getApplication()).getApplicationComponent())
            .build()
            .inject(this);

在MainActivity中我也是如上所述,但是我在其中创建了一个活动组件的getter。

然后在我的每个片段中,我实例化如下:

    DaggerFragmentComponent.builder()
            .homeFragmentModule(new HomeFragmentModule(this))              
    .activityComponent(((MainActivity)getActivity()).getActivityComponent())
            .build()
            .inject(this);

此时一切正常。我可以注入演示者和我想要的任何东西,但我不确定它是否是正确的方法。

您如何看待我的实施?

此外,我还有一个Repository类,将在每个Presenter中使用,以显示从Firebase到UI的信息。

您是否会为此创建一个组件和模块,然后使所有片段都依赖于它?

希望我没有提出太多问题,但我真的想清理我的想法。

谢谢

1 个答案:

答案 0 :(得分:2)

您的设置非常好。绝对是我见过的最好的。

我想建议一些细微的改变,从长远来看,这将使你的生活更轻松。

子组件而非组件依赖项:

我还没有看到一个用例,其中指定组件之间的依赖关系比使用子组件更好。

子组件可以直接访问父组件的整个对象图。这有两个好处:

  1. 可以轻松使用父提供的对象(零代码)
  2. 可以轻松更改对象的范围(例如,将某个对象移动到Application组件以使其全局化)
  3. 约定优于配置的一般原则适用于这种情况,有利于子组件。

    无需区分活动和碎片:

    我注意到Activities所需的对象图通常与Fragments所需的对象图非常相似。

    在我的MVC / MVP方法中,我将Activities和Fragments指定为控制器,并且只有一个ControllerComponent用于将依赖项注入控制器。

    然而,即使使用另一种MVC / MVP方法(或根本没有),如果从概念上考虑它们 - 活动和片段具有非常相似的功能。

    因此,我建议使用一个单独的组件来注入活动和碎片。

    每个片段不需要模块:

    我已经回答了有关每个活动/片段here有一个组件/模块的问题。请阅读该答案 - 它还提供了与此相关的代码示例以及上述所有建议。

    恕我直言,模块应按问题域对依赖关系进行分组,而不是由将使用它们的组件进行分组。例如,电子商务应用可以包含以下模块:NetworkingModuleCurrencyModuleCartModuleCheckoutModule等等。

    真实实施示例:

    前段时间我开源了我自己的应用程序,而且,恕我直言,它具有相对较好的依赖注入结构。您可以查看此结构here

    这个DI结构的一个方面我还不满意的是并非所有依赖关系都是按域分布在模块中的。你可以做得更好。

    订阅我的博客:

    我觉得插上这个有点不舒服,但我们现在正在Dagger上录制一个高级视频教程。我们上个月一直在研究这个教程,它应该在2-3周内准备就绪。

    本教程将准确讨论您的要求 - 如何构建Dagger代码以实现可维护性。您可以在www.techyourchance.com订阅我的博客,以便在发布时收到通知。

    希望这会有所帮助。