0
votes

I'm new to Dagger and trying to use dagger2 for DI, but looks like it injected a null presenter to my activity. Below is my codes.

public class TasksActivity extends AppCompatActivity {

@Inject
TasksContract.Presenter mTasksPresenter;
......

@Override
protected void onCreate(Bundle savedInstanceState) {
    ... ...

    DaggerTasksComponent.builder()
            .appComponent(MyApp.getAppComponent())
            .tasksModule(new TasksModule())
            .build()
            .inject(this);

   ... ...
}

Module for TasksActivity:

 @Module
    public class TasksModule {

    @Provides
    @ActivityScoped
    TasksContract.Presenter providePresenter(TaskDataRepository taskDataRepository, TasksContract.View view) {
        return new TasksPresenter(taskDataRepository, view);
    }

    @Provides
    @ActivityScoped
    TasksContract.View provideView() {
        return new TasksFragment();
    }
}

Component for TasksActivity:

@ActivityScoped
    @Component (modules = TasksModule.class, dependencies = AppComponent.class)
    public interface TasksComponent {
        void inject(TasksActivity activity);
    }

I also have an AppModule and AppComponent for application level dependency injection such as TaskDataRepository. And annotated them with @Singleton.

2
does dagger throw an exception? is your build successful? did you provide your repository and view properly? - seyed Jafari

2 Answers

2
votes

Create a constructor on your TaskModule passing this parameters taskDataRepository and view, then use that on your TaskModule. So your initialization should look like this

  DaggerTasksComponent.builder()
            .appComponent(MyApp.getAppComponent())
            .tasksModule(new TasksModule(taskDataRepository, view))
            .build()
            .inject(this);
0
votes

You should provide your repository and view to your module in order for injection to work. there are 2 ways to do it in your case:

  1. use module parameter(not advised)

    @Module
    public class TasksModule {
    
    private final TaskDataRepository taskDataRepository;
    private final TasksContract.View view;
    
    public TasksModule(TaskDataRepository taskDataRepository, TasksContract.View view){
    this.taskDataRepository = taskDataRepository;
    this.view = view;
    

    }

    @Provides
    @ActivityScoped
    TasksContract.Presenter providePresenter(TaskDataRepository taskDataRepository, TasksContract.View view) {
        return new TasksPresenter(taskDataRepository, view);
    }
    
    @Provides
    @ActivityScoped
    TasksContract.View provideView() {
        return new TasksFragment();
    }
    

    }

and then your activity code for building component will look like:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    ... ...

    DaggerTasksComponent.builder()
        .appComponent(MyApp.getAppComponent())
        .tasksModule(new TasksModule(new TaskDataRepository(), new TasksFragment()))
        .build()
        .inject(this);

      ... ...
    }
  1. Use @BindsInstance annotation (preferred):

In order to use bindsInstance you change your activity component a bit:

@ActivityScoped
@Component (modules = TasksModule.class, dependencies = AppComponent.class)
public interface TasksComponent {
    void inject(TasksActivity activity);

    @Component.Builder
    interface Builder {
        @BindsInstance Builder taskRepository(TaskDataRepository taskDataRepository);
        @BindsInstance Builder activity(TaskActivity activity);
        TasksComponent build();
  }
}

since we are using bindsInstance annotation we can change our module methods to static too:

@Module
public abstract class TasksModule {

@Provides
@ActivityScoped
static TasksContract.Presenter providePresenter(TaskDataRepository taskDataRepository, TasksContract.View view) {
    return new TasksPresenter(taskDataRepository, view);
}

@Provides
@ActivityScoped
static TasksContract.View provideView() {
    return new TasksFragment();
}
}

and lastly your component builder will look like this:

DaggerTasksComponent.builder()
    .appComponent(MyApp.getAppComponent())
    .activity(this)
    .taskRepository(new TaskDataRepository())
    .build()
    .inject(this);

for further reading please refer to docs and other samples

hope it helped