Search code examples
androiddagger-2

Project structure with Dagger2


I'm learning how to use Dagger2 and MVP, so i created project, contains one main activity with viewPager and two fragments.

Code is working, but i'm think i do something wrong when i create my Dagger classes. I think if i contunue, a create a monster =)

I'm asking you help to comment my code architecture, associated with Dagger2. Maybe this question should be on CodeReview: if so, i del and move it.

Ok, i show it step by step. Main suspicions of bad code on step 3.

At the first, main activity called HomeActivity, and fragment(i show one) called HomePacksFragment. App about animals, and fragment show packs of them, it's why it called so.

1) I have two modules: PresentersModule, provide presenters for HomeActivity and HomePacksFragment:

@Module
public class PresentersModule {
    @Provides
    HomePresenter provideHomePresenter(AnimalDatabase animalDatabase) {
        return new HomePresenter(animalDatabase);
    }

    @Provides
    HomePacksFragmentPresenter provideHomePacksFragmentPresenter(AnimalDatabase animalDatabase) {
        return new HomePacksFragmentPresenter(animalDatabase);
    }
}

and RoomModule prodive access to database and DAO:

@Module
public class RoomModule {
    private AnimalDatabase db;

    public RoomModule(Application mApplication) {
        db = Room.databaseBuilder(mApplication,
                AnimalDatabase.class, AnimalDatabase.DATABASE_NAME)
                .allowMainThreadQueries()
                .fallbackToDestructiveMigration()
                .build();
    }

    @Singleton
    @Provides
    AnimalDatabase providesRoomDatabase() {
        return db;
    }

    @Singleton
    @Provides
    DAO providesProductDao(AnimalDatabase db) {
        return db.daoAccess();
    }
}

2) Then i have component AppComponent who knows all my modules and can inject dependences in concrete view:

@Singleton
@Component(modules = {PresentersModule.class, RoomModule.class})
public interface AppComponent {
    void injectsHomeActivity(HomeActivity homeActivity);
    void injectsHomePacksFragment(HomePacksFragment homePacksFragment);

    DAO animalDao();
    AnimalDatabase animalDatabase();
}

3) Then i have class AnimalsLibraryApp extended Application, and this is the place i make wrong in my opinion.

public class AnimalsLibraryApp extends Application {
    private static AnimalsLibraryApp instance;
    private static AppComponent homeActivityComponent;
    private static AppComponent homeFragmentPacksComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;

        if (BuildConfig.DEBUG) {
            Timber.plant(new Timber.DebugTree());
        }
        createHomeActivityComponent();
        createHomePacksComponent();
    }

    public static AnimalsLibraryApp getInstance() {
        return instance;
    }

    public static AppComponent getHomeActivityComponent() {
        return homeActivityComponent;
    }

    public static AppComponent getHomeFragmentPacksComponent() {
        return homeFragmentPacksComponent;
    }

    private void createHomeActivityComponent() {
        homeActivityComponent = DaggerAppComponent.builder()
                .presentersModule(new PresentersModule())
                .roomModule(new RoomModule(instance))
                .build();
    }

    private void createHomePacksComponent() {
        homeFragmentPacksComponent = DaggerAppComponent.builder()
                .presentersModule(new PresentersModule())
                .roomModule(new RoomModule(instance))
                .build();
    }
}

Idea of this class was provide singletons of AppComponent. Technicaly it works, but what if i have 10 or 20 views? Class, extended Application is basic class, it will not contain only AppComponent create logic, so much more will be here. Do i write it correct?

4) It's end. I create my HomeActivity and inject dependences with simple(is't it?) line.

public class HomeActivity extends AppCompatActivity implements HomeContract.View {
    @Inject
    HomePresenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);

        AnimalsLibraryApp.getHomeActivityComponent().injectsHomeActivity(this);

        presenter.attachView(this);
        presenter.viewIsReady();

        DatabaseUtils.copyDatabase(this, AnimalDatabase.DATABASE_NAME);

        ViewPager viewPager = findViewById(R.id.pager);

        HomeMenuAdapter myPagerAdapter = new HomeMenuAdapter(getSupportFragmentManager());
        viewPager.setAdapter(myPagerAdapter);
        TabLayout tabLayout = findViewById(R.id.tablayout);
        tabLayout.setupWithViewPager(viewPager);

        tabLayout.getTabAt(0).setIcon(R.drawable.help);
        tabLayout.getTabAt(1).setIcon(R.drawable.help);
    }
}

I do right things or i must to change something until it's not too late?

UPD:

Ok, i google to simple Dagger 2 examples and found this App class version:

public class MyApp extends Application {
    private static MyApp app;
    private AppModule appModule;
    private BasicComponent basicComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        app = this;

        appModule = new AppModule(this);
        basicComponent = DaggerBasicComponent.builder()
                .appModule(appModule)
                .build();
    }

    public static MyApp app() {
        return app;
    }

    public AppModule appModule() {
        return appModule;
    }

    public BasicComponent basicComponent() {
        return basicComponent;
    }

It's look like better and cleaner that my, but i have a question. In this example we always retutn basicComponent, so it means that it must included all modules? It's normal practice to create "god" component? =)

If i have 3 modules, i need to write(for my example):

appComponent = DaggerAppComponent
                .builder()
                .appModule(appModule)
                .presentersModule(new PresentersModule())
                .roomModule(new RoomModule(this))
                .build();

Solution

  • According to my idea and the reference as you said you are using AnimalsLibraryApp in a bad way. In the application class, you just need to declare one dagger component then in every view, you will inject the module with that component in the view. If you google a dagger2 sample and check the class that extended the application you will understand.