Reputation: 9069
On Android, When using Dagger2, I have to call the following line on every activities that uses apiService
:
@Inject
public ApiService apiService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerApiComponent.builder()
.activityModule(new ActivityModule(this))
.build()
.inject(this);
//...
}
How can I summarize it to something like:
DaggerApiComponent.builder()
.activity(this)
.build()
.inject(this);
or even simpler to something like:
MyApplication.injectApiService(this);
How should I change my component and modules to use Dagger2 with less copy-pasting code in my activities?
Here is my ApiComponent
:
@Singleton
@Component(modules = ApiModule.class)
public interface ApiComponent {
void inject(MainActivity activity);
void inject(...
}
Here is ApiModule
:
@Module(includes = {RetrofitModule.class, ActivityModule.class})
public class ApiModule {
@Singleton
@Provides
public static ApiService provideApiService(Activity activity) {
//...
}
}
and ActivityModule
:
@Module
public class ActivityModule {
private final Activity context;
public ActivityModule(Activity context) {
this.context = context;
}
@Singleton
@Provides
public Activity provideActivityContext() {
return context;
}
}
Upvotes: 2
Views: 816
Reputation: 1888
The approach of such "DI" has two problems:
Activity
) should not know where the @Inject
instance is from, what it cares about is just "hey, give me an instance of it".To resolve above problems, dagger.android
comes to the rescue.
AndroidInjector
for each component.// App component
@Singleton
@Component(
modules = [
AndroidSupportInjectionModule::class, // build-in module
ActivityBindingModule::class,
AppModule::class
]
)
interface AppComponent : AndroidInjector<MainApplication> {
// we need to bind `MainApplication` instance to this component,
// so we have a builder here.
@Component.Builder
abstract class Builder : AndroidInjector.Builder<MainApplication>()
}
// Each controller (e.g. `Activity` / `Fragment` / `Service`) subcomponents
@Module
abstract class ActivityBindingModule {
// will generate a FooActivitySubcomponent under ActivityBindingModule's component
@ActivityScoped
@ContributesAndroidInjector(modules = [FooModule::class])
internal abstract fun fooActivity(): FooActivity
@ActivityScoped
@ContributesAndroidInjector(modules = [BarModule::class])
internal abstract fun barActivity(): BarActivity
}
AndroidInjector
s, so it can do injection for us using provided injector in step 1.// App component
class MainApplication : DaggerApplication() {
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerAppComponent.builder().create(this)
}
}
// Each controller subcomponents
class FooActivity : DaggerAppCompatActivity() {
@Inject lateinit var foo: Foo
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// no need to call inject() here anymore!
foo.doSth()
}
}
For a concrete example: check out iosched
Upvotes: 1