如何使用 dagger2 注入没有任何 activity 或片段的 java class

How to inject into a java class that doesn't have any activity or fragment using dagger2

Android Studio 2.2.2

我有一个NewsListModelImpclass是MVP中的模型

我想将我的改造服务注入到模型中。但是,由于 NewsListModelImp 不包含对上下文或 activity 的任何引用,我无法调用 getApplication()。如果你在 activity 或片段中,你会这样做。我不想在 NewsListModeImp 的构造函数中传递任何上下文或 activity,因为它必须来自演示者,我想避免那里有任何 android 东西。

public class NewsListModelImp implements NewsListModelContract {
    @Inject
    NYTimesSearchService mNYTimesSearchService;

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

我的申请class

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 注释注释,构造函数的参数也将被注入。

假设在您要注入的应用程序中:

@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:

注释
public class NewsListModelImp implements NewsListModelContract {

    NYTimesSearchService mNYTimesSearchService;

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

然后一切都将正确注入。

为什么要将参数作为构造函数的参数传递给class?这样的设计模式符合SOLID principles。对象依赖项被注入到对象中,而不是在对象内部创建,这样的代码很容易测试(在测试中,依赖项可以被 Mock 替换)

额外信息:

可以注入实现特定接口的对象。 here 描述了这种技术。在你的情况下 NyTimesPresenter 可以有 NewsListModelContract 因为它是依赖而不是 NewsListModelImp。为此,请将另一个模块添加到您的 AppComponent:

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

AppComponent 提供具体 class 实现接口的方法应该如下所示:

@Singleton
@Module
public abstract class AppModule {

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

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

public class NyTimesPresenter {

    NewsListModelContract newsListModel;

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