0

I am trying out dagger2 and want to inject a presenter into the activity, i searched the internet as to why the presenter is null but then i get different implementations of injecting an activity with several modules. Can someone please help me understand where i am going wrong when trying to create the dagger dependencies?

I have the following classes defined:

ActivityComponent.class

@PerActivity
@Component(modules = {ActivityModule.class}, dependencies = {AppComponent.class, GitHubComponent.class})
public interface ActivityComponent {
    void inject(AppCompatActivity activity);
}

ActivityModule.class

@Module
public class ActivityModule {
    private AppCompatActivity activity;

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

    @Provides
    AppCompatActivity provideActivity() {
        return activity;
    }

    @Provides
    @PerActivity public MainView provideMainView() {
        return new MainViewImpl(activity);
    }

    @Provides
    @ActivityScope
    Context providesContext() {
        return activity;
    }

}

AppModule.class

@Singleton
@Module
public class AppModule {
    private final GitHubApp application;

    public AppModule(final GitHubApp application) {
        this.application = application;
    }

    @Provides
    Application provideApplication() {
        return application;
    }

    @Provides
    public GitHubLog provideGithubLog() {
        return new GitHubLog();
    }
}

GitHubModule.class

@Module
public class GitHubModule {
    @Provides
    public MainInteractor provideMainInteractor() {
        return new MainInteractorImpl();
    }

    @Provides
    @PerActivity
    public MainPresenter provideMainPresenter(){
        return new MainPresenterImpl();
    }
}

AppComponent.class

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    void inject(GitHubApp gitHubApp);

    void inject(GitHubLog gitHubLog);

    Application application();

    GitHubLog getGitHubLog();
}

GithubComponent.class

@Component(modules = {GitHubModule.class, AppModule.class})
public interface GitHubComponent {
    void inject(MainPresenterImpl presenter);
}

Inside the application class, i am created an appcomponent instance and also githubcomponent instance, that i use in the BaseActivity to create the activitycomponent.

And i inject the presenter inside MainAcitivity that extends BaseActivity and i get a null-pointer exception saying presenter is null.

Is my implementation incorrect? What could i be missing?

EDIT: GithubApp.class

public class GitHubApp extends Application {
    public static GitHubApp INSTANCE;
    private AppComponent appComponent;
    private GitHubComponent gitHubComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        INSTANCE = this;
        getAppComponent().inject(this);
    }

    public AppComponent getAppComponent() {
        if (appComponent == null) {
            appComponent = DaggerAppComponent.builder()
                    .appModule(new AppModule(this))
                    .gitHubModule(new GitHubModule())
                    .build();
        }

        return appComponent;
    }

    public GitHubComponent getGitHubComponent() {
        if (gitHubComponent == null) {
            gitHubComponent = DaggerGitHubComponent.builder()
                    .gitHubModule(new GitHubModule())
                    .build();
        }
        return gitHubComponent;
    }
}

How i inject the presenter into the activity is as under: BaseActivity.class has a method that returns the activity component

return DaggerActivityComponent.builder()
            .appComponent(((GitHubApp)getApplication()).getAppComponent())
            .gitHubComponent(((GitHubApp)getApplication()).getGitHubComponent())
            .activityModule(new ActivityModule(this))
            .build();

In the MainActivity.class i use it like this: before super.onCreate() is called, call getActivityComponent().inject(this);

@Inject MainPresenter mainPresenter is the variable declaration

EDIT2:

Changes suggested by Chisko and Muhammad Babar work together, as it is also required to change the inject(AppCompatActivity activity) to inject(MainActivity activity)

2 Answers2

1

Besides the comments, I think you are also missing additional setup:

GitHubApp.java

GitHubAppComponent component;

// call this inside onCreate()
private void setupComponent() {
    component = DaggerGitHubAppComponent.builder()
        .gitHubModule(new GitHubModule(this))
        .build();
}

public GitHubAppComponent getComponent() {
     return component;
}

As well as the activity component, which needs an abstract method on a BaseActivity you create:

BaseActivity.java

abstract void setupComponent(GitHubAppComponent appComponent);

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    GitHubApp app = (GitHubApp) getApplication();
    GutHubAppComponent component = app.getComponent();
    setupComponent(component);
}

Then, your activities should also create the component:

MainActivity.java

@Override
protected void setupComponent(GitHubAppComponent appComponent) {
    ActivityComponent component = DaggerMainActivityComponent.builder()
        .gitHubAppComponent(appComponent)
        .activityModule(new ActivityModule(this))
        .build()
    component.inject(this);
}

I know it might appear like a pain in the a$$, but once you master Dagger you'll find out how easy and convenient it is.

Chisko
  • 3,092
  • 6
  • 27
  • 45
  • But, activity module takes a this, that would point to the activity, then how would that be accepted in the GitHubApp.class ? – Rat-a-tat-a-tat Ratatouille Mar 15 '18 at 05:32
  • @Rat-a-tat-a-tatRatatouille corrected typo. That's what you meant right? – Chisko Mar 15 '18 at 05:36
  • `// call this inside onCreate() private void setupComponent() { component = DaggerGitHubAppComponent.builder() .activityModule(new AppModule(this)) .build(); } public GitHubAppComponent getComponent() { return component; }` -> i was referring to this, i am sorry, i think i donot understand this part – Rat-a-tat-a-tat Ratatouille Mar 15 '18 at 05:43
  • I mean that you need to call `setupComponent()` inside `onCreate()` in your `GitHubApp` class – Chisko Mar 15 '18 at 05:44
  • yes, so `setUpComponent`, has the method `activityModule(new AppModule(this))`, in the current code base, `AppModule` -> which is `Acitivity Module` accepts an `activity`, not an application class – Rat-a-tat-a-tat Ratatouille Mar 15 '18 at 05:47
  • There are two `setupComponent` methods, one that takes no arguments in your `Application` class, and the other that takes the application component as argument and that goes in your activities – Chisko Mar 15 '18 at 05:48
  • yeah, so i added this code, and also changed from AppCompatActivity.class to MainActivity.class as per @MuhammadBabar it worked. – Rat-a-tat-a-tat Ratatouille Mar 15 '18 at 05:55
  • I guess the only missing part was the `inject()` call. But the architecture I explained here will make things easy for you. At least has done for me. – Chisko Mar 15 '18 at 05:57
  • sure yes, thanks a lot.. how do i give points to both u and @MuhammadBabar in this case? – Rat-a-tat-a-tat Ratatouille Mar 15 '18 at 05:59
  • Well, I bothered to post an answer, and went a bit further than that :) I guess it's up to you. – Chisko Mar 15 '18 at 06:00
1

In your ActivityComponent replace void inject(AppCompatActivity activity) with void inject(MainActivity activity).

Muhammad Babar
  • 8,084
  • 5
  • 39
  • 56