I just started to learn how to use Dagger, and I have converted my Backend connection class to be injected automatically.
That class handles Retrofit and performs network requests. It used to have static methods but now it is an object, e.g.:
Backend.fetchPost(context, 42); // old way
mBackend.fetchPost(42); // mBackend is an injected field
The context is used to retrieve the AccountManager which provides the OAuth token with my backend server. This is now injected automatically.
That works well in activities and fragments but I can't figure out how to inject my SyncAdapter class.
Indeed, it is a framework object that I don't have control over, and AndroidInjections doesn't have a static method ready to inject that kind of class.
Here's the code that I would like to get to work:
/**
* Handle the transfer of data between the backend and the app, using the Android sync adapter framework.
*/
public class SyncAdapter extends AbstractThreadedSyncAdapter {
@Inject
public Backend mBackend; // can't use constructor injection,
// so might aswell use a public field
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
}
public SyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {
super(context, autoInitialize, allowParallelSyncs);
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
List<Post> posts = mBackend.getPosts();
// do stuf with the posts
}
}
So I know I should call @#!.inject(this) somewhere in the constructor, but I don't know exactly how I'm supposed to do this:
- use a static field on the application class to retrieve the head of the dependency graph, and let it browse it until it can inject all the fields
- create a factory class and interfaces like the one used for activities and fragments
- something else?
More details about my dagger2 implementation:
the
Backendclass has an@Injectconstructor, so dagger should be able to construct it provided it can get instances of the API and the Gson parser:@Inject public Backend(BackendApi api, @UploadGson Gson uploadGson) { mApi = api; mUploadGson = uploadGson; }- the
BackendModuledagger module has@Providemethods for a@UploadGson Gsonobject, and the dependency list from aBackendApi(retrofit) to the application class (through various objects such as injectors or loggers) - the
BackendModule.classis referenced in themodules = {}declaration of the application@Component
So basically, given an application object, dagger should be able to instantiate an object of the class Backend, which I want to inject into my SyncAdapter class.
I just don't know how to actually trigger the injection.
PS: as stated, I learned Dagger yesterday, so please advise if you think that my implementation is broken.
I think I went too fast posting here. I thought the framework instantiated my
SyncAdapter, however I'm doing it myself:So I just need to inject the service and I'm done. Here's how to fix that:
Here's the sync adapter: the default constructor was hidden (made private) and the new constructor is crafted for Dagger: it expects directly
SyncServiceas a context and injects the backend and other objects (in my case, a repository class).New subcomponent for Service injection:
Here's the module that references that subcomponent. It provides the
SyncService(andAuthenticatorService, which is implemented in the exact same behavior) expected by theSyncAdapterconstructor (resp.Authenticator):So the sync adapter has the following dependencies:
ServicesModuleMaybe this can help someone.