问题
I am trying to use Dagger 2 for instantiating a Retrofit interface. The CloudContactDataStore
class injects the RestClient
and calls its methods.
When I instantiate a CloudContactDataStore
object, its RestClient
attribute has null
value.
public class CloudContactDataStore implements ContactDataStore {
@Inject RestClient restClient;
public CloudContactDataStore() {
this.initializeInjector();
}
private void initializeInjector() {
ApiComponent component = DaggerApiComponent.builder()
.apiModule(new ApiModule())
.build();
component.inject(this); // Nothing changes, restClient is null!
this.restClient = component.getRestClient(); // This works
}
}
Here is how I create the Dagger Module and Component:
@Singleton
@Component(modules = ApiModule.class)
public interface ApiComponent {
void inject(ContactDataStore contactDataStore);
RestClient getRestClient();
}
@Module
public class ApiModule {
@Provides public RestClient provideRestClient(ApiService apiService) {
return new RestClientImpl(apiService);
}
@Provides public ApiService provideApiService(RestAdapter restAdapter) {
return restAdapter.create(ApiService.class);
}
@Provides public RestAdapter provideRestAdapter() {
return RestApiAdapter.getInstance();
}
}
So, why the inject
function does not work but calling component
's getRestClient()
yes?
回答1:
I find it's very useful to look at the code that Dagger 2 generates as it's quite easy to follow and can often point you in the right direction.
Dagger 2 creates code much like you'd write so think about how you would implement ApiComponent.inject(ContactDataStore)
. Assuming within that method you had access to a RestClient how would you get it into the field? If you sat and wrote it you'd notice that you have to do something like this:
((CloudContactDataStore) contactDataStore).restClient = restClient;
Or in other words you'd need to cast it down to a specific implementation. Dagger 2 doesn't cast down, EVER (at least I've not seen it), because that is usually unsafe.
So, you have two choices. Change the inject(ContactDataStore)
method to inject(CloudContactDataStore)
, or provide a method on ContactDataStore
that allows the RestClient
to be passed in.
Update: Its not possible to @Inject through abstract, i.e. interface, method.
If you want to inject it through the ContactDataStore
API then you have a problem as there is currently a restriction in Dagger 2 (have raised a feature request to remove it) that you cannot mark an abstract method with @Inject
. So, in the meantime (or forever if there is some reason why it cannot work in Dagger 2) you will need to do it manually, i.e. get the instance of RestClient
from your component method and pass it to the appropriate method on the interface.
来源:https://stackoverflow.com/questions/32947791/why-dagger-inject-is-not-working-but-component-getobject-yes