My software specifications are as follows:
Android Studio 3.4
dagger-android 2.16
I have the following class that passes a MapboxGeocoder
that will execute and return a response.
class GeocodingImp(private val mapboxGeocoder: MapboxGeocoder) : Geocoding {
override fun getCoordinates(address: String, criteria: String): AddressCoordinate {
val response = mapboxGeocoder.execute()
return if(response.isSuccess && !response.body().features.isEmpty()) {
AddressCoordinate(
response.body().features[0].latitude,
response.body().features[0].longitude)
}
else {
AddressCoordinate(0.0, 0.0)
}
}
}
However, the MapboxGeocoder
is generated in a dagger module at compile time. So I have to specify the string for the address and TYPE_ADDRESS
.
@Reusable
@Named("address")
@Provides
fun provideAddress(): String = "the address to get coordinates from"
@Reusable
@Provides
@Named("geocoder_criteria")
fun provideGeocoderCriteria(): String = GeocoderCriteria.TYPE_ADDRESS
@Reusable
@Provides
fun provideMapboxGeocoder(@Named("address") address: String, @Named("geocoder_criteria") geocoderCriteria: String): MapboxGeocoder =
MapboxGeocoder.Builder()
.setAccessToken("api token")
.setLocation(address)
.setType(geocoderCriteria)
.build()
@Reusable
@Provides
fun provideGeocoding(mapboxGeocoder: MapboxGeocoder): Geocoding =
GeocodingImp(mapboxGeocoder)
my component
class:
interface TMDispatchMobileUIComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: TMDispatchMobileUIApplication): Builder
fun build(): TMDispatchMobileUIComponent
}
fun inject(application: TMDispatchMobileUIApplication)
}
In the main activity I would use this like this as the user can enter in a different address or change the criteria to something else. But as the module are compiled I cannot pass any parameters to them at runtime:
presenter.getAddressCoordinates("this should be the actual address", GeocoderCriteria.TYPE_ADDRESS)
For my injection into the Activity I use the following:
AndroidInjection.inject(this)
Is there any solution to this problem?
With the @Inject annotation on the constructor, we instruct Dagger that an object of this class can be injected into other objects. Dagger automatically calls this constructor, if an instance of this class is requested.
Now Component in a Dagger works by creating a graph of all the dependencies in the project so that it can find out where it should get those dependencies when they are needed. In order to implement this, an interface needs to be created and should be annotated with @Component.
In Dagger, we create scope annotations such as ActivityScope, FragmentScope to specify the lifecycle, but hilt provides us with core components such as Application, Activity, Fragment, Service, and View.
The problem you have can be solved using "Assisted injection" approach.
It means that you need a class to be built both using dependencies provided from the existing scopes and some dependencies from the instance's creator, in this case, your main activity. Guice from Google has a nice description of what it is and why it is needed
Unfortunately, Dagger 2 does not have this feature out from the box. However, Jake Wharton is working on a separate library that can be attached to Dagger. Moreover, you can find more details in his talk on Droidcon London 2018, where he dedicated a whole talk section for this question: https://jakewharton.com/helping-dagger-help-you/
You can recreate your whole component at runtime if you wish, where you'd then pass in the parameters to your module as a constructor parameter. Something like:
fun changeAddress(address: String) {
val component = DaggerAppComponent.builder() //Assign this to wherever we want to keep a handle on the component
.geoModule(GeoModule(address))
.build()
component.inject(this) //To reinject dependencies
}
And your module would look like:
@Module
class AppModule(private val address: String) {...}
This method may be wasteful though, if you're creating many different objects in your component.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With