如何使用dagger2注入没有任何活动或片段的Java类 [英] How to inject into a java class that doesn't have any activity or fragment using dagger2

查看:74
本文介绍了如何使用dagger2注入没有任何活动或片段的Java类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Android Studio 2.2.2

我有一个 NewsListModelImp 类是MVP中的模型。

I have a NewsListModelImp class which is the model in the MVP.

我想将改造服务注入模型中。但是,由于 NewsListModelImp 不包含对上下文或活动的任何引用,因此无法调用 getApplication()。如果您处于活动或片段中,该怎么办。我不想在 NewsListModeImp 的构造函数中传递任何上下文或活动,因为那必须来自演示者,并且我想避免在那里出现任何Android东西。

I want to inject my retrofit service into the model. However, as NewsListModelImp doesn't contain any reference to a context or activity I cannot call getApplication(). Which is what you would do if you were in a activity or fragment. I don't want to pass any context or activity in the constructor of NewsListModeImp as that would have to come from the presenter and I want to avoid any android stuff there.

public class NewsListModelImp implements NewsListModelContract {
    @Inject
    NYTimesSearchService mNYTimesSearchService;

    public NewsListModelImp() {
        ((NYTimesSearchApplication)getApplication()).getAppComponent().inject(this);
    }
}

我的应用程序类

public class NYTimesSearchApplication extends Application {
    private AppComponent mAppComponent;

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

        /* Setup dependency injection */
        createAppComponent();
    }

    private void createAppComponent() {
        mAppComponent = DaggerAppComponent
                .builder()
                .retrofitModule(new RetrofitModule())
                .build();
    }

    public AppComponent getAppComponent() {
        return mAppComponent;
    }
}

我的提供模块

@Module
public class RetrofitModule {
    private Retrofit retrofit() {
        return new Retrofit
                .Builder()
                .baseUrl(Constants.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

    @Provides
    @Singleton
    public NYTimesSearchService providesNYTimesSearch() {
        return retrofit().create(NYTimesSearchService.class);
    }
}

我的应用组件

@Singleton
@Component(modules = {RetrofitModule.class})
public interface AppComponent {
    void inject(NewsListModelImp target);
}

非常感谢您的建议,

推荐答案

Dagger-2 可以正常运行。因此,如果在 Activity (或 Fragment )内部注入了对象,并且其构造函数正确地用进行了注释@Inject 批注,构造函数的参数也将被注入。

Dagger-2 works reccurently. So if inside Activity (or Fragment) object is injected and it's constructor is properly annotated with @Inject annotation, the constructor's parameters will be injected too.

假设您要在应用程序内部注入:

Suppose inside the application you would like to inject:

@Inject NyTimesPresenter presenter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ((NYTimesSearchApplication) getApplication()).getAppComponent().inject(this);
}

NyTimesPresenter 必须使用 @Inject 进行注释:

public class NyTimesPresenter {

    NewsListModelImp newsListModel;

    @Inject
    public NyTimesPresenter(NewsListModelImp newsListModel) {
        this.newsListModel = newsListModel;
    }
}

NewsListModelImp 构造函数还必须使用 @Inject 进行注释:

NewsListModelImp constructor must also be annotated with @Inject:

public class NewsListModelImp implements NewsListModelContract {

    NYTimesSearchService mNYTimesSearchService;

    @Inject
    public NewsListModelImp(NYTimesSearchService nYTimesSearchService) {
        this.mNYTimesSearchService = nYTimesSearchService;
    }
}

然后将正确注入所有内容。

Then everything will be injected properly.

为什么要将参数作为构造函数的参数传递给类?这种设计模式符合 SOLID原则 。对象依赖项被注入到对象中,而不是在对象内部创建,并且这样的代码易于测试(在测试中,依赖项可以替换,即用 Mock 's)

Why the parameters should be passed to class as constructors' parameters? Such design pattern conforms SOLID principles. Object dependencies are injected into objects and not created inside it and such code is easily testable (in tests dependencies can be replaced ie. by Mock's)

附加信息:

可以注入实现特定接口的对象。 此处描述了这种技术。在您的情况下, NyTimesPresenter 可以具有 NewsListModelContract 作为其依赖项,而不是 NewsListModelImp 。为此,向您的 AppComponent 中添加另一个模块:

It is possible to inject objects implementing specific interfaces. Such technique is described here. In your case NyTimesPresenter can have NewsListModelContract as it's dependency instead of NewsListModelImp. To do this add another module to your AppComponent:

@Singleton
@Component(
        modules = {
                RetrofitModule.class,
                AppModule.class
        })
public interface AppComponent {

AppComponent 方法应如下所示:

@Singleton
@Module
public abstract class AppModule {

    @Binds
    public abstract NewsListModelContract provideNewsListModelContract(NewsListModelImp newsListModelImp);
}

NyTimesPresenter的实现应该更改(只是用它实现的接口替换具体的类):

The implementation of NyTimesPresenter should change (just to replace concrete class with interface it implements):

public class NyTimesPresenter {

    NewsListModelContract newsListModel;

    @Inject
    public NyTimesPresenter(NewsListModelContract newsListModel) {
        this.newsListModel = newsListModel;
    }
}

这篇关于如何使用dagger2注入没有任何活动或片段的Java类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆