Reputation: 335
I have my NetworkDataSource
which I want to inject. I want to use constructor injection because I'm the owner of this class:
public class NetworkDataSource {
@Inject
public NetworkDataSource(String url, String method) {
this.url = url;
this.method = method;
}
}
The thing is that the arguments of this constructor (which are the dependencies) are retrieved from a Service
as extras when a BroadcastIntent
is triggered. So my question is, how could I provide these arguments retrieved from the Service
to my NetworkDataSource
constructor injection?
The Service
looks like this:
public class Service extends IntentService {
// I would like to inject NetworkDataSource
//@Inject
//NetworkDataSource netWorkDataSource;
public String url;
public String method;
@Override
protected void onHandleIntent(Intent workIntent) {
url = workIntent.getStringExtra("url");
method = workIntent.getStringExtra("method");
}
............
............
networkDataSource.myMethod();
}
Thank you.
Upvotes: 1
Views: 830
Reputation: 81588
It's a tricky question because you'd think Dagger primarily solves the problem that now you no longer need to introduce "Factory" classes in order to re-configure behavior.
However, you actually still need to use "Factory" classes to create objects with dynamic constructor arguments that are obtained at runtime.
So:
public class NetworkDataSource {
@Inject
public NetworkDataSource(String url, String method) {
this.url = url;
this.method = method;
}
}
Would be
@Singleton
public class NetworkDataSourceFactory {
private final OkHttpClient okHttpClient;
private final Gson gson;
@Inject
public NetworkDataSourceFactory(OkHttpClient okHttpClient, Gson gson) {
this.okHttpClient = okHttpClient;
this.gson = gson;
}
public NetworkDataSource create(String url, String method) {
return new NetworkDataSource(okHttpClient, gson, url, method);
}
}
Then now you can inject NetworkDataSourceFactory
, and create a NetworkDataSource
when you receive your arguments:
@Inject NetworkDataSourceFactory factory;
....
networkDataSource = factory.create(url, method);
Supposedly you can use AutoFactory
to help with creating the factory, but I haven't used it yet, all I know is that it exists for this particular usecase.
EDIT: you can also check out https://github.com/square/AssistedInject to help with this problem.
Upvotes: 2
Reputation: 2085
Let's do it step by step. (All code will be in kotlin
)
First of all, you have
class NetworkDataSource(val url: String, val method: String)
and need dagger module, which is responsible to create it
@Module
class NetworkModule {
@Provides
fun dataSource(@Named("url") url: String,
@Named("method") method: String): NetworkDataSource {
return NetworkDataSource(url, method)
}
}
after that you need dagger component
@Component(modules = [NetworkModule::class])
interface NetworkComponent {
fun inject(service: Service)
@Component.Builder
interface Builder {
@BindsInstance
fun url(@Named("url") url: String): Builder
@BindsInstance
fun method(@Named("method") method: String): Builder
fun build(): NetworkComponent
}
}
Now you can inject it inside Service
class Service : IntentService {
@Inject
lateinit var netWorkDataSource: NetworkDataSource
override protected fun onHandleIntent(workIntent: Intent) {
val url = workIntent.getStringExtra("url")
val method = workIntent.getStringExtra("method")
DaggerNetworkComponent.builder()
.url(url)
.method(method)
.build()
.inject(this)
}
}
That's it.
Upvotes: 1