Use Dagger Provider with Android Material Stepper

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

@Module
class 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