On an Android project, I am using android-material-stepper from StepStone. I am also using dependency injection with dagger.
I was facing the following problem : How to properly inject Fragments
without the need to create a DaggerComponent
for each of them ?
Providers are here to help. This is how I am doing
class StepFragmentBL @Inject constructor() : Fragment(), Step, BlView {
@Inject lateinit var blPresenter: BlPresenter
...}
This is one of the Fragment I am creating. We can see the @Inject constructor
with @Inject lateinit
var that shows that this object is injectable by dagger. It is also implementing Step
to be used by StepperLayout
and implements another interface.
class BlPresenter @Inject constructor
BlPresenter is a simple injectable class
@Singleton@Component(modules = [(DeliveryModule::class)])interface DeliveryComponents {
fun inject(deliveryActivity: DeliveryActivity)}
This is the component injecting my Activity
@Moduleclass DeliveryModule(private val activity: DeliveryActivity) {
@Named("Activity") @Provides internal fun providesContext(): Context { return activity }
@Provides fun providesFragmentManager(): FragmentManager { return activity.supportFragmentManager }}
class DeliveryActivity : AppCompatActivity() {
@Inject lateinit var deliveryPresenter: DeliveryPresenter
private lateinit var deliveryComponents: DeliveryComponents
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_home)
di() ui() }
private fun di() { deliveryComponents = DaggerDeliveryComponents.builder() .deliveryModule(DeliveryModule(this)) .build() deliveryComponents.inject(this) }
private fun ui() { Timber.v(Info.getMethodName()) stepperLayout.adapter = deliveryPresenter.stepperAdapter }}
We are creating the component into the Activity
here. Then, presenter for this activity is also injected
class DeliveryPresenter @Inject constructor() {
@Inject lateinit var stepperAdapter: PickingStepperAdapter
}
We are arriving to a StepperAdapter
instance, also injected
private const val NB_FRAG = 2
class PickingStepperAdapter @Inject constructor( fm: FragmentManager, @Named("Activity") context: Context) : AbstractFragmentStepAdapter(fm, context) {
/** * Provider for Fragment */ @Inject lateinit var blFragmentProvider: Provider<StepFragmentBL>
/** * Provider for Fragment */ @Inject lateinit var pdtFragmentProvider: Provider<StepFragmentPdt>
override fun getCount(): Int { return NB_FRAG }
override fun createStep(position: Int): Step { Timber.v("${Info.getMethodName()} $position")
return when (position) { 0 -> blFragmentProvider.get() else -> pdtFragmentProvider.get() } }}
Here, we are just using
@Inject lateinit var blFragmentProvider: Provider<StepFragmentBL>
to tell dagger to create the code that will provide an instance of fragment each time blFragmentProvider.get()
will be called. Indeed, this is called here
return when (position) { 0 -> blFragmentProvider.get() else -> pdtFragmentProvider.get() }
Like this, dagger is injecting fragment for us, and we don’t have to care about objects creation