I'm testing about dagger.android. I wonder how to add custom module having constructor.
In usual, when we use AndroidInjection.inject(activity), It declares all module has no constructor, right?
example
@Module class ApiModule {
@Provides fun retrofit(): Retrofit = Retrofit.Builder().build()
}
But in my case, I have some module having constructor
example
@Module class SomeModule(private val a : InterfaceA, private val b : InterfaceB) {
@Provides fun a() : InterfaceA = a
@Provides fun b() : InterfaceB = b
}
InterfaceA and InterfaceB need to be declared in Activity or Fragment
So now it has a big problem when doing injection.
class Presenter @Inject internal constructor(private val a : InterfaceA, private val b : InterfaceB) {
// do something....
}
// before dagger.android
class AppActivity : Activity {
@Inject lateinit var presenter : Presenter
override fun onCreate(bundle: Bundle?) {
super.onCreate(bundle)
DaggerAppActivityComponent.builder()
.SomeModule(SomeModule(a = xxx, b = yyy)
.inject(this)
}
}
// after dagger.android
class AppActivity : DaggerActivity {
@Inject lateinit var presenter : Presenter
override fun onCreate(bundle: Bundle?) {
super.onCreate(bundle)
}
}
My question is this :
When we need module having custom constructor but its arguments cannot produce in dagger-graph. If we use AndroidInjection.inject(), then how do we add that module?
There currently isn't a way to do this. How do you know what values to pass to the module? Are they a function of the Activity, or the Activity's Intent? If so, then you can use the activity binding do retrieve them in a provides method
It's google's sample of todo-mvp-dagger
TaskPresenter's constructor is this:
@Inject
TasksPresenter(..., TasksContract.View tasksView) {
mTasksView = tasksView;
}
It's what TasksContract.View is :
public class TasksFragment extends Fragment implements TasksContract.View {}
TaskPresenterModule is :
public TasksPresenterModule(TasksContract.View view) {
mView = view;
}
@Provides TasksContract.View provideTasksContractView() { return mView; }
finally, DI code is this :
DaggerTasksComponent.builder()
.tasksRepositoryComponent(((ToDoApplication) getApplication()).getTasksRepositoryComponent())
.tasksPresenterModule(new TasksPresenterModule(tasksFragment)).build()
.inject(this);
This pattern is usual of Android-MVP.
so now, dagger-android cannot support special component injection of MVP.
Can you add a module like this to your subcomponent:
@Module
public abstract class TasksModule {
@Provides
static TasksContract.View provideTasksContractView(TasksActivity activity) {
return (TasksFragment) activity.getFragmentManager().findFragmentById(R.id.contentFrame);
}
}
@ronshapiro
I hope modules separate from android.content.Context.
but I will try it.
@ZeroBrain in that case, could we just provide TasksContract.View on TasksFragmentModule instead of TasksPresenterModule?
@Module
class TasksFragmentModule {
@Provides
fun provideTasksView(tasksFragment: TasksFragment): TasksContract.View = tasksFragment
@Provides
fun provideTasksPresenter(tasksRepository: TasksRepository, tasksView: TasksContract.View): TasksContract.Presenter {
return TasksPresenter(tasksRepository, tasksView)
}
}
Most helpful comment
Can you add a module like this to your subcomponent: