Dagger 2和接口实现

R. *_*ang 7 java mvp android dependency-injection dagger-2

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

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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

@Inject MainPresenter presenter;
Run Code Online (Sandbox Code Playgroud)

所以我可以用另一个(调试或测试)实现来切换这个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();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在出现的问题是OkHttpClient不再被注入.当然我可以改变模块以接受参数OkHttpClient,但我不认为这是建议的方法.有没有理由为什么MainPresenterImpl没有正确注入?

mos*_*vax 5

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

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

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

它当前不抛出错误的原因是因为如果并且不是注入目标的某处,MainPresenterImpl 则可以满足OkHttpClient依赖性。Dagger 无法为接口类型创建成员注入方法,因为作为接口,它不能具有可注入字段,并且它不会自动注入实现类型的字段,因为它只是提供提供者方法返回。MainPresenterImplMainPresenter


Epi*_*rce 5

您可以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);
}
Run Code Online (Sandbox Code Playgroud)