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