android - 使用适用于 Android MVP 的 Dagger 2 设置模块和组件 - 具有多个 fragment 的 Activity

标签 android mvp dagger-2 dagger

我使用 Dagger 2 已经有一段时间了,但我仍在尝试解决一些问题。有一件事我还是不太擅长 正在为不同的情况设置模块和组件,例如具有多个 fragment 的 Activity 。 我见过很多实现,但大多数时候都有些不同。

那么,让我公开一下我当前使用 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 个 fragment ,我将为 fragment 创建 3 个模块和 1 个组件

@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,首先在我的应用程序类中,然后在每个 Activity 和 fragment 中

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

例如在 WelcomeActivity 中,我这样实例化它:

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

在 MainActivity 中,我做的和上面一样,但我正在为其中的 Activity 组件创建一个 getter。

然后在我的每个 fragment 中我都这样实例化:

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

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

您如何看待我的实现?

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

您会为此创建一个组件和模块,然后让所有 fragment 都依赖于它吗?

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

谢谢

最佳答案

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

我想提出一些小的改变,从长远来看会让你的生活更轻松。

子组件而不是组件依赖:

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

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

  1. 使使用父级提供的对象变得容易(零代码)
  2. 可以轻松更改对象的范围(例如,将某些对象移动到 Application 组件以使其成为全局对象)

约定优于配置的一般原则适用于这种有利于子组件的情况。

无需区分 Activity 和 Fragments:

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

在我的 MVC/MVP 方法中,我将 Activity 和 Fragments 指定为 Controller ,并有一个 ControllerComponent 用于将依赖项注入(inject) Controller 。

然而,即使使用另一种方法实现 MVC/MVP(或根本不使用),如果您从概念上考虑它们——Activity 和 Fragments 具有非常相似的功能。

因此,我建议使用一个组件来注入(inject) Activity 和 Fragment。

不需要每个 fragment 一个模块:

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

恕我直言,模块应该按问题域对依赖项进行分组,而不是按将使用它们的组件。例如,电子商务应用程序可能具有以下模块:NetworkingModuleCurrencyModuleCartModuleCheckoutModule、等等……

实际实现示例:

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

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

订阅我的博客:

我觉得在这里插入这个有点不舒服,但我们现在正在录制有关 Dagger 的高级视频教程。过去一个月我们一直在编写本教程,它应该会在 2-3 周内准备就绪。

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

希望这对您有所帮助。

关于android - 使用适用于 Android MVP 的 Dagger 2 设置模块和组件 - 具有多个 fragment 的 Activity ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44615986/

相关文章:

python - 模型- View -呈现器和三层?

java - @Inject 注释如何知道在同一接口(interface)下实例化哪个具体类?

android - 如何从android中的视频中捕获帧?

Android 创建类似 Spotify 的 slider 菜单

android - Kotlin 中的 DialogFragment.onDismiss() 空指针异常

cocoa - Cocoa MVC 真的不是 MVP 吗?

java - 从Android发送时间数据类型到mySQL数据库

c# - 在 Model View Presenter 模式中,一个 Presenter 可以同时使用两个不同的 View 界面吗?

Java + Android Jetpack + Dagger 2 在 ViewModel 中注入(inject)

java - 如何使用 Dagger2 绑定(bind)到具有多个 ViewModelFactory 的 map