Dagger and mvp - should presenter use dagger for i

2019-07-15 08:19发布

I'm starting to think in mvp, dagger should not be used in the presenter. The usual way to construct dagger is using a global component and have subcomponents for scoping the graph. This global component will take an applicationContext as a parameter on creating the appmodule.java class usually. Having the application context given makes life easier.

That's all fine but if I use a module from the global component or even a subcomponent, the context should be passed in. So that means if I inject the presenter with dagger it will be tied to the applicationContext. THIS MAKES IT DIFFICULT TO TEST as junit. Android code should not be in presenter.

So I'm asking is the best practice to just use dagger in activities fragments broadcast receivers and services only? Speaking in terms of mvp architecture that is. The other solution could be to design another dagger component but not a subcomponent that is not related to appcomponent or an applicationContext. What is the common practice?

UPDATE: LETS look at a real example:

usually we'd create a appComponent that's close in application override like this:

public class MyApplication extends Application {

    private AppComponent appComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        appComponent = initDagger(this);
    }

    public AppComponent getAppComponent() {
        return appComponent;
    }

    protected AppComponent initDagger(PomeloApplication application) {
        return DaggerAppComponent.builder()
                .appModule(new AppModule(application))
                .build();
    }}

and then for example in the presenter we'd do this in the constructor:

public WelcomePresenter(Context context) {
        super(context);
        presenterComponent = ((MyApplication) context).getAppComponent();
        presenterComponent.inject(this);
    }

so because I wanted the application Context for dagger providers I ended up forcing callers to depend on a context Object. Basically, you cant get the AppComponent modules until you get a context so you can cast it as "MyApplication" and inject from the component? So i was thinking why is this dagger pattern making me force the presenter to have a context?

Even if we used a subComponent it would still depend on the AppComponent and then in our test case we'd have to deal with an application context being created to get dagger to inject.

So I think there should be a rule - in MVP prefer manual constructor injection over dagger injection Because class shouldn’t have knowledge about how it is injected. Something being injected should not care about how it is injected.

dagger.android outlines the problem i am talking about as per the accepted answer.

2条回答
何必那么认真
2楼-- · 2019-07-15 08:47

I also agree with the statement "Not having android related code in your presenter is always a good idea, and dagger does not interfere with that."

First, what I want to draw attention that starting from dagger version 2.10 you can use dagger.android package which simplifies injection in the activities and fragments, so you don't need to use MyApplication casting across the app.

Second, why are you not injecting WelcomePresenter into activity or fragment but vice versa?

查看更多
叛逆
3楼-- · 2019-07-15 08:57

Dependency injection is useful for Android components (activities, etc.) primarily because these classes must have a no-arg constructor so the framework can construct instances of them. Any class that isn't required to have a no-arg constructor should simply receive all its dependencies in its constructor.

Edit: A side note about how you're getting a reference to the AppComponent.

Application is-a Context, and the Context returned by Context#getApplicationContext() is usually the Application instance. But this is not necessarily the case. The one place I know of where it may not be the case is in an emulator. So this cast can fail:

presenterComponent = ((MyApplication) context).getAppComponent();

Mutable static fields are evil in general, and even more so on Android. But IMO, the one place you can get away with it is in your Application class. There is only one instance of Application, and no other component will ever exist before Application#onCreate() is called. So it's acceptable to make your AppComponent a static field of MyApplication, initialize it in onCreate(), and provide a static getter, as long as you only call the getter from the lifecycle methods of other components.

查看更多
登录 后发表回答