简体   繁体   中英

Port from Dagger 2 to Android Dagger 2.11

I cannot get my head around how to setup a couple of things when porting the code from Dagger 2 to Android Dagger 2.11. In Dagger 2 the setup was something like this:

public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        this.initializeInjector();
    }

    private void initializeInjector() {

        //this class should be auto-generated by Dagger on build
        this.applicationComponent = DaggerApplicationComponent.builder()
                .applicationModule(new ApplicationModule(this))
                .netModule(new NetModule())
                .build();
    }

    public ApplicationComponent getApplicationComponent() {
        return this.applicationComponent;
    }
}

You then had access to the applicationComponent and you could inject any object by using the:

getApplicationComponent().inject(MyCustomObject);

In Android Dagger 2.11 you don't do that anymore. For Activities and Fragments you can inject with the AndroidInjector.inject() method but what about other types? Let's look at an example below. We have a JobManager that can post jobs. The jobs are persisted to a file and when they should be posted they are first deserialized. The problem is that its dependencies are not set of course. So the question is: How to do that?

public class JobManager {

    private Context context;

    @Inject
    public JobManager(Context context) {
        this.context = context;
    }

    public void postJob(String jobId) {

        MyJob myJob = deserializePersistedJobFromFile(jobId);


        //((App) context).getApplicationComponent().inject(myJob); //This was the old way of doing injection
        AndroidInjector.inject(myJob); //This doesn't work - what to do now?

    }

    .
    .
    .

}

public class MyJob {

    @Inject
    ApiService apiService;

    .
    .
    .
}

You can get Dagger to inject a MembersInjector<T> and then use that to inject dependencies into your own objects...

public class JobManager {

    private Context context;

    @Inject
    public JobManager(Context context, MembersInjector<MyJob> jobInjector) {
        this.context = context;
    }

    public void postJob(String jobId) {

        MyJob myJob = deserializePersistedJobFromFile(jobId);
        jobInjector.inject(myJob);
    }

    .
    .
    .

}

Is there any problem you experience with the "old" approach that makes you want to move to the "new" one?

I couldn't find one single real advantage in performing dependency injection using the static AndroidInjector class, but it does increase the complexity of the code.

Therefore, if you don't have a very specific reason to move in that direction, I would suggest to stay with the "old" working approach.

As for injection into non-Activity/Fragment classes, I think you shouldn't use DI framework for this. Use Dagger for injection into Application, Activity, Fragment and Service only. More information available in this post: Dependency Injection in Android .

Writing this on a phone so apologies for any typos.

TL;DR Would it not make sense that, MyJob needs an @Inject(ed) constructor that takes the ApiService , rather than a member injection? Is there a reason why MyJob can't have it's own constructor? (Unfamiliar if this is an Android SDK class or not). If that's not the answer then I have another observation that your JobManager seems to do what the JobScheduler does? Unless it's simply a confusion of terms (ie both "jobs")

Outside of Android and it's lifecycle uniqueness dependency inversion's most common use is constructor injection. Learning the DI pattern within the Android framework isn't the best introduction and you get caught up in the 'lying to the complier' DI framework functionality that is meant to simply help move off a legacy codebase (cf Dagger 1's static injection or Guide's 'private' member injection).

As a side note, I have avoided moving to "Android Dagger" since it seems to go against having modular separation of code. I think I have more to learn here but right now the boilerplate distruption advantage of "Android Dagger" is outweighed by my need for loosely coupled feature modules to support Instant Apps and an altogether more modular code base.

Hope that helps a bit.

I wrote this article which should be helpful to you. It links to the sample code on Github.

https://proandroiddev.com/exploring-the-new-dagger-android-module-9eb6075f1a46

Pay close attention to the AppModule and how it keeps track of the application so you can pass application.getApplicationContext() into constructors for your JobManager

Using dagger android library has advantages :

1) Using dagger violates dependency injection principle that classes shouldn't know about how dependencies are injected, this violation can be fixed using dagger android library

2) Dagger code can be decoupled from android components.

3) Clean code can be achieved as you don't need to initialize dagger components and call inject methods in android components, leading to creation of easy to maintain apps.

You can decouple dagger from android using dagger android components such as DaggerActivity,DaggerApplication, and DaggerFragment and moving AndroidInjection.inject() calls to central location, instead of calling in each and every activity and fragment, by using activity lifecycle callback on application.

You can read detailed explanation about dagger android at http://www.zoftino.com/android-framework-classes-dependency-injection-using-dagger-android

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM