Dagger 2: Difference between revisions
Line 91: | Line 91: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
'''Failing to pass external dependencies will fail at runtime and not build time''' | '''Failing to pass external dependencies will fail at runtime and not build time''' | ||
=Inject= | |||
The original class looked like this | |||
<syntaxhighlight lang="kotlin"> | |||
class EpisodeListPresenter( | |||
private val episodeService: EpisodeService, | |||
private val schedulers: SchedularsBase, | |||
private val dbRepo: DbRepo) | |||
) | |||
</syntaxhighlight> | |||
To build this class previously we were using Dagger getting the components and returning the class | |||
<syntaxhighlight lang="kotlin"> | |||
fun EpisodeListFragment.buildPresenter(): EpisodeListContract.Actions { | |||
// Build the component | |||
val component = DaggerAppComponent | |||
.builder() | |||
.contextModule(ContextModule(activity?.applicationContext!!)) | |||
.build() | |||
return EpisodeListPresenter( | |||
component.episodeService(), | |||
component.schedules(), | |||
component.dbRepo() | |||
) | |||
} | |||
</syntaxhighlight> | |||
Using the @Inject we can modify the component class to provide the method we need so do this. So instead of | |||
<syntaxhighlight lang="kotlin"> | |||
class EpisodeListPresenter( | |||
private val episodeService: EpisodeService, | |||
private val schedulers: SchedularsBase, | |||
private val dbRepo: DbRepo) | |||
) | |||
</syntaxhighlight> | |||
We can have this in our component because the constructor of the class will provide which bits to use | |||
<syntaxhighlight lang="kotlin"> | |||
class EpisodeListPresenter( | |||
private fun buildEpisodeDetailPresenter():EpisodeDetailPresenter | |||
private fun buildEpisodeListPresenter():EpisodeDetailListPresenter | |||
) | |||
</syntaxhighlight> | |||
Now the constructor can look like this | |||
<syntaxhighlight lang="kotlin"> | |||
class EpisodeListPresenter @Inject constructor( | |||
private val episodeService: EpisodeService, | |||
private val schedulers: SchedularsBase, | |||
private val dbRepo: DbRepo) | |||
) | |||
</syntaxhighlight> | |||
<syntaxhighlight lang="kotlin"> | |||
fun EpisodeListFragment.buildPresenter(): EpisodeListContract.Actions = | |||
DaggerAppComponent() | |||
.builder() | |||
.contextModule(ContextModule(activity?.applicationContext!!)) | |||
.build() | |||
.buildEpisodeListPresenter() | |||
</syntaxhighlight> |
Revision as of 00:17, 20 December 2020
Introduction
Dagger is made by Google. Dagger allows you to
- Scope dependencies
- Bind single instance to life cycles
- Only need to build them once
- Generates the code at compile time
Example Without Dagger
fun buildCar: Car =
Car(SturdyFrame(),
Wheels(),
RocketEngine())
With Dagger
fun buildCar: Car =
DaggerAppComponent
.builder()
.build()
.buildCar()
Modules
Modules in Dagger are responsible for providing object we want to inject. They contain the methods which return the objects.
Modules are decorated with @module and the objects are decorated with @provides
@Module
fun CarModule {
@Provides
fun provideEngine() : Engine = Engine()
@Provides
fun provideFrame() : Frame = Frame()
@Provides
fun provideWheels() : Wheels = Wheels()
@Provides
fun provideCar(engine: Engine, wheels: Wheels, frame: Frame) : Car {
return Car(frame, wheels, engine)
}
}
To share a module across modules add the include to the modules decorator
@Module(includes = [EngineModule::class])
fun CarModule {
@Provides
fun provideFrame() : Frame = Frame()
...
@Provides
fun provideCar(engine: Engine, wheels: Wheels, frame: Frame) : Car {
return Car(frame, wheels, engine)
}
}
Components
A Dagger Component is something which contains a set of modules.
The component is an interface which allows access to our module instances. The underlying code is generated at build time so the interface is simple to write. We just need the @Component keyword and the modules required
@Component(modules = [
NetworkModule::class,
ContextModule::class,
CarModule::class ])
interface AppCommponent {
fun okHttpClient(): okHttpClient
fun car(): Car
...
}
When creating a component we only need to list the dependencies at the top as Dagger knows to include child dependencies.
Using the component we just to the following
class SomeActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
var component = DaggerAppComponent
.builder()
.contextModule(ContextModule(context!!)),
.networkModule(NetworkModule()),
.build()
var car = component.car()
var client = component.OkHttpClient()
}
}
Failing to pass external dependencies will fail at runtime and not build time
Inject
The original class looked like this
class EpisodeListPresenter(
private val episodeService: EpisodeService,
private val schedulers: SchedularsBase,
private val dbRepo: DbRepo)
)
To build this class previously we were using Dagger getting the components and returning the class
fun EpisodeListFragment.buildPresenter(): EpisodeListContract.Actions {
// Build the component
val component = DaggerAppComponent
.builder()
.contextModule(ContextModule(activity?.applicationContext!!))
.build()
return EpisodeListPresenter(
component.episodeService(),
component.schedules(),
component.dbRepo()
)
}
Using the @Inject we can modify the component class to provide the method we need so do this. So instead of
class EpisodeListPresenter(
private val episodeService: EpisodeService,
private val schedulers: SchedularsBase,
private val dbRepo: DbRepo)
)
We can have this in our component because the constructor of the class will provide which bits to use
class EpisodeListPresenter(
private fun buildEpisodeDetailPresenter():EpisodeDetailPresenter
private fun buildEpisodeListPresenter():EpisodeDetailListPresenter
)
Now the constructor can look like this
class EpisodeListPresenter @Inject constructor(
private val episodeService: EpisodeService,
private val schedulers: SchedularsBase,
private val dbRepo: DbRepo)
)
fun EpisodeListFragment.buildPresenter(): EpisodeListContract.Actions =
DaggerAppComponent()
.builder()
.contextModule(ContextModule(activity?.applicationContext!!))
.build()
.buildEpisodeListPresenter()