Setting Up Modules and Components with Dagger 2 for Android MVP - Multiple Fragment Activity

I have been working with Dagger 2 for a while and I am still trying to figure out some things. One thing I still don't manage very well is configuring modules and components for different situations, like an activity with multiple fragments. I have seen many implementations and most of the time it is slightly different.

So let me expose my current application structure that uses MVP and I would like some opinions if my implementation is ok or not.

@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();

}

      

In this AppModule, I usually only install the Singleton that my application will need. Like SharedPreferences or anything related to network requests. This module and component is standard and I always start my applications and create them like this.

Then I install my module and component for Activity, which will have a dependency on 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);
}

      

Now MainActivity has 3 fragments and I will create 3 modules for fragments and 1 component

@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);
}

      

Then I will have to instantiate the dagger, first in my application class and then in each of the actions and fragments

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

      

For example, in WelcomeActivity, I create it like this:

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

      

In MainActivity, I do it the same way as above, but I create a getter for the activity component inside it.

Then, in each of my fragments, I create an instance like this:

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

      

At this point everything works fine. I can inject Speakers and whatever I want, but I'm not sure if this is the right approach.

What do you think of my implementation?

Also I have one repository class that will be used in each Presenter to display information from Firebase to the UI.

Could you create a component and a module for this and then make all the fragments dependent?

I hope I didn't ask too many questions, but I would love to clear my ideas.

thank

+3


source to share


1 answer


Your setup is not bad. Definitely among the best I've seen.

I would like to suggest some minor changes that will make your life easier in the long run.

Subcomponents instead of component dependencies:

I have not yet seen a use case where defining dependencies between components is better than using subcomponents.

Subcomponents have direct access to the entire object graph of the parent component. This has two advantages:

  • allows easy use of objects provided by parents (zero code)
  • makes it easy to change the scope of an object (for example, move some object to an application component to make it global)

In this case, the general convention over configuration applies in favor of subcomponents.

There is no need to distinguish between actions and fragments:

I noticed that the graph of objects required by actions is usually very similar to the one required for fragments.

In my MVC / MVP approach, I designate actions and fragments as controllers and have one controller that is used to inject dependencies into controllers.

However, even using a different approach to MVC / MVP (or nothing at all) if you think of them conceptually - actions and fragments have very similar functionality.



Therefore, I suggest having one component that injects both actions and fragments.

No need for module per fragment:

I have already answered the question about having one component / module per Activity / Fragment here . Please read this answer - it also contains code examples that are relevant to this and all of the above suggestions.

IMHO, modules should group dependencies by domain, not by the component that will use them. For example, e-commerce application may have the following modules: NetworkingModule

, CurrencyModule

, CartModule

, CheckoutModule

, etc.

An example of a real implementation:

I opened up my own application a while ago and IMHO it has a relatively good dependency injection structure. You can view this structure here .

One aspect of this DI structure that I am not yet satisfied with is that not all dependencies are propagated across modules across domains. You can do it better.

Subscribe to my blog:

I feel a little uncomfortable to plug this in here, but we are currently recording a preliminary video tutorial on the dagger. We have been working on this tutorial for the last month and should be ready in 2-3 weeks.

In this tutorial, we'll discuss exactly what you asked for - how to structure your dagger code for maintainability. You can subscribe to my blog at www.techyourchance.com to be notified of its release.

Hope it helped.

+2


source







All Articles