匕首 2 注入构造函数

我开始在我正在开发的应用程序中使用Dagger 2,但我对Dagger 2的工作原理有一些疑问。

我了解了@Provides方法背后的所有逻辑,以及用于初始化依赖项的@Inject注释,但是对类构造函数的@Inject注释有点让我感到困扰。

例如:

我的应用程序,我定义了一个模块,ContextModule,用于检索我的应用程序的上下文:

上下文模块.java

@Module
public class ContextModule {

    private final Context context;

    public ContextModule(Context context) {
        this.context = context;
    }

    @Provides
    public Context context() {
        return this.context;
    }
}

这个模块由我的BaseActivityComponent使用:

基本活动组件.java

@BaseActivityScope
@Component(modules = ContextModule.class)
public interface BaseActivityComponent {
    void injectBaseActivity(BaseActivity baseActivity);
}

目前为止,一切都好。。然后我有一个AuthController类,这取决于上下文,我想把它注入到我的BaseActivity中。因此,在我的AuthControllers中.class我有这样的东西:

public class AuthController {

    private Context context;

    @Inject
    public AuthController(Context context) {
        this.context = context;
    }

    public void auth() {
        // DO STUFF WITH CONTEXT
    }
}

我把它注入到我的BaseActivity中,比如:

public class BaseActivity extends AppCompatActivity {

    @Inject
    AuthController authController;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        BaseActivityComponent component = DaggerBaseActivityComponent.builder()
            .contextModule(new ContextModule(this))
            .build();

        component.injectBaseActivity(this);

        authController.auth();

    }
}

现在我的问题是,匕首如何知道我的AuthControllers是BaseActivity的依赖关系?只需声明

@Inject
AuthController authController;

这就像我创建了一个控制器模块一样:

@Module(includes = ContextModule.class)
public class ControllerModule {

    @Provides
    AuthController authController(Context context) {
        return new AuthController(context);
    }

}

然后在我的BaseActivityComponent中,我会添加我的AuthController getter并将我的依赖模块更改为ConsordersModule:

@BaseActivityScope
@Component(modules = ControllersModule.class)
public interface BaseActivityComponent {

    void injectBaseActivity(BaseActivity baseActivity);

    AuthController getAuthController();
}

当我调用 injectBaseActivity(this) 时,它会“告诉”dagger,所有@Inject注释都是我的类的依赖项,然后它会搜索我的项目,以查找与该类型匹配@Inject注释构造函数?

我认为Dagger 2的一个好处是模块文件可以用作我的依赖项三的“文档”。但是,如果只是在我控制的所有构造函数中添加@Inject,那么将来会不会有点混乱,因为你不知道什么实际上取决于什么?(我的意思是,你知道什么取决于什么,你只需要浏览很多文件才能真正找出答案)

在构造函数中使用@Inject注释或何时在模块文件中添加@Provides方法时,是否有任何最佳实践?我在构造函数中使用@Inject,我不需要更改模块文件中的构造函数定义,但是有什么缺点吗?

谢谢。


答案 1

当我调用 injectBaseActivity(this) 时,它会“告诉”dagger,所有@Inject注释都是我的类的依赖项,然后它会在我的项目中搜索与该类型匹配@Inject注释构造函数?

完全。但是当你调用 时,它不会完成,但这一切都发生在编译时。这是注释处理的一种方法(另一种方法是在运行时使用反射)。injectBaseActivity

当您构建项目时,您在build.gradle文件中包含的匕首注释处理器(作为依赖项)被调用,其中包含由注释注释的所有字段,类等的列表,并使用它构建依赖项图。然后,它解析图形,生成提供图形上项的所有依赖项的源代码。@Inject

injectBaseActivity只是执行之前生成的代码,并将所有依赖项分配给您的对象。这是适当的源代码,您可以读取和调试。

简单地说,这是一个编译步骤的原因是性能和验证。(例如,如果你有一些依赖周期,你会得到一个编译错误)


匕首如何知道我的AuthControllers是BaseActivity的依赖关系?

@Inject
AuthController authController;

通过注释字段匕首,您知道您想要一个 .目前为止,一切都好。现在,Dagger 将寻找一些提供控制器的方法,在组件、组件依赖项和组件模块中查找它。它还将查看是否可以单独提供该类,因为它知道其构造函数。@InjectAuthController

如果您不在任何模块中包含对象构造函数,dagger 如何知道它?

@Inject
public AuthController(Context context) { /**/ }

通过使用 inject 注释构造函数,您还告诉 dagger 有一个调用的类,您需要一个上下文来实例化它。它基本上与将其添加到模块中相同。AuthController

如果您没有源代码来仅将注释添加到构造函数,或者如果对象需要进一步初始化,则应使用模块方法。或者就您而言...@Provides@Inject

[...]模块文件可以用作我的依赖关系树的“文档”[...]

是的,你当然可以这样做。但是随着项目的发展,你将不得不维护大量不必要的代码,因为同样的事情也可以通过构造函数上的简单注释来完成。

在构造函数中使用@Inject注释或何时在模块文件中添加@Provides方法时,是否有任何最佳实践?

如果你想为不同的上下文提供不同的版本(例如,以2种不同的方式实现接口),还有一个注释,告诉dagger您希望提供哪个类作为实现。@Binds

除此之外,我认为您应该尽可能始终使用构造函数注入。如果某些内容发生更改,则不必触及代码的任何其他部分,并且您编写的代码更少,因此可以包含错误的地方更少。

此外,Dagger可以通过了解更多来优化很多,如果你实现不必要的代码,它将不得不处理你引入的开销。


当然,最后一切都取决于你认为最好的。毕竟,您必须使用代码;)


答案 2