Dagger 2 和接口实现

Dagger 2 and interface implementations

我有一个简单的 Dagger 2 测试设置,基于 http://konmik.github.io/snorkeling-with-dagger-2.html。 它注入一个输出所有首选项的 PreferenceLogger。在注入的class中,我可以@Inject more classes.

public class MainActivity extends Activity {
    @Inject PreferencesLogger logger;
    @Inject MainPresenter presenter;

    @Override protected void onCreate(Bundle savedInstanceState) {
    MyApplication.getComponent().inject(this);
    presenter.doStuff();
        logger.log(this);
    }
}


public class PreferencesLogger {

    @Inject OkHttpClient client;
    @Inject public PreferencesLogger() {}

    public void log(Contect context) {
    // this.client is available
    }
}

当我 运行 设置记录器时,在 PreferencesLogger.log 中正确设置了 OkHttpClient。 所以这个例子按预期工作。 现在,我正在尝试建立一个 MVP 结构。 有一个带有实现的 MainPresenter 接口。在 MainActivity 中我设置了一个:

@Inject MainPresenter presenter;

所以我可以用替代(调试或测试)实现切换此 MainPresenter。当然,现在我需要一个模块来指定我想要使用的实现。

public interface MainPresenter {
    void doStuff();
}

public class MainPresenterImpl implements MainPresenter {

    @Inject OkHttpClient client;

    public MainPresenterImpl() {}

    @Override public void doStuff() {
    // this.client is not available    
    }
}


@Module public class MainActivityModule {
    @Provides MainPresenter provideMainPresenter() {
        return new MainPresenterImpl();
    }
}

现在出现了一个问题,即不再注入 OkHttpClient。当然,我可以更改模块以接受参数 OkHttpClient,但我认为这不是建议的方法。 MainPresenterImpl 无法正确注入是否有原因?

与构造函数注入不同,无法自动注入在 @Provides 方法中构造的依赖项的 @Inject 注释字段。能够注入字段需要一个在其模块中提供字段类型的组件,而在提供者方法本身中,这样的实现是不可用的。

presenter 字段被注入 MainActivity 时,所发生的只是调用提供者方法并将 presenter 设置为其 return 值。在您的示例中,无参数构造函数不进行初始化,提供程序方法也不进行初始化,因此不进行初始化。

但是,提供者方法确实可以通过其参数访问模块中提供的其他类型的实例。我认为在 provider 方法中使用参数实际上是 "inject" 所提供类型的依赖项的建议(甚至是唯一)方法,因为它明确地将它们指示为模块中的依赖项,这允许 Dagger 抛出错误如果不能满足,则在编译时。

它目前没有抛出错误的原因是因为 MainPresenterImpl 可以 满足其 OkHttpClient 依赖关系,如果 MainPresenterImpl 而不是MainPresenter 是某个地方的注入目标。 Dagger 不能为接口类型创建成员注入方法,因为作为一个接口,它不能有可注入字段,它不会自动注入实现类型的字段,因为它只是提供任何提供者方法returns.

您可以使用构造函数注入来注入您的 MainPresenterImpl

/* unscoped */
public class MainPresenterImpl implements MainPresenter {

    @Inject 
    OkHttpClient client;

    @Inject
    public MainPresenterImpl() {
    }

    @Override public void doStuff() {
       // this.client is now available! :)
    }
}


@Module 
public class AppModule {
    private MyApplication application;

    public AppModule(MyApplication application) {
        this.application = application;
    }

    @Provides
    /* unscoped */ 
    public MyApplication application() {
        return application;
    }
}

@Module 
public abstract class MainActivityModule {
    @Binds public abstract MainPresenter mainPresenter(MainPresenterImpl mainPresenterImpl);
}