当前位置: 首页 > 面试题库 >

Dagger 2注入构造器

楚羽
2023-03-14
问题内容

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

我得到了@Provides方法和@Inject批注背后的所有逻辑来初始化您的依赖关系,但是类构造函数的@Inject批注使我感到烦恼。

例如:

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

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使用此模块:

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;

这就像我创建一个ControllerModule一样:

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

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

}

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

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

    void injectBaseActivity(BaseActivity baseActivity);

    AuthController getAuthController();
}

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

我认为有关Dagger
2的一件好事是,模块文件可用作我的依赖项3的“文档”。但是,如果仅在我控制的所有构造函数中添加@Inject,将来它不会变得有些混乱,因为您不知道实际上取决于什么?(我的意思是,您知道什么取决于什么,您只需要浏览很多文件即可真正找出来)

在构造函数中使用@Inject批注或在Modules文件中添加@Provides方法时,是否有最佳实践?我在构造函数中使用@Inject可以得到这些信息,而无需在我的Module文件中更改构造函数定义,但是有什么缺点吗?

谢谢。


问题答案:

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

究竟。但这在您调用时还没有完成injectBaseActivity,而是全部在编译时发生。这是 注释处理的 一种方式(另一种在运行时使用反射)。

在构建项目时,您在build.gradle文件中包含(作为依赖项)的dagger-annotation-
processor将被调用,并带有注释所@Inject注释的所有字段,类等的列表,并以此构建依赖关系图。然后,它解析该图,生成提供该图上项目所有依赖项的源代码。

injectBaseActivity只需执行之前生成的代码,并将所有依赖项分配给您的对象。它是正确的源代码,您可以阅读和调试。

简而言之,这是编译步骤的原因是性能和验证。(例如,如果您有一些依赖周期,则会出现编译错误)

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

@Inject
AuthController authController;

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

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

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

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

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

[…]模块文件可用作我的依赖项树的“文档” […]

是的,您当然可以这样做。但是随着项目的增长,您将必须维护 许多 不必要的代码,因为在构造函数上使用简单的注释也可以完成相同的操作。

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

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

除此之外,我相信您应该尽可能使用构造函数注入。如果有什么变化,您不必接触代码的任何其他部分,并且只需编写较少的代码,因此可以减少包含错误的位置。

此外,Dagger可以而且确实可以通过了解更多信息来进行很多优化,并且,如果您实现了不必要的代码,则它必须与您引入的开销一起工作。

当然,最终取决于您的最佳想法。毕竟, 必须使用 您的 代码;)



 类似资料:
  • 我有很多Android ViewModel类,它们往往有很多依赖项(大多数是Room中的DAO,每个SQLite表一个)。有些依赖项超过10个。 这很好,但Inject构造函数充满了参数,并且只包含样板代码,用于从构造函数参数设置注入的成员。 我想切换到“常规”注入成员,使用注释单独标识,就像其他(哑)类一样。 这对于与Android相关的类(尽管ViewModel被宣传为非Android依赖,例

  • 我刚开始使用Dagger并尝试使用dagger2进行DI,但看起来它给我的活动注入了一个空演示器。下面是我的代码。 公共类TasksActivity扩展AppCompatActivity{

  • 我把下面的内容看做是构造函数和setter注入的区别之一。有人能用一些简单的例子解释一下下面的区别吗,我对术语完全功能对象和不完全对象有点困惑。 -

  • 请帮助理解在哪种情况下我应该使用构造函数注入和设置器注入。请帮我举个合适的例子。 先谢谢你。

  • 主要内容:输出注入是将依赖注入对象的过程。构造函数注入很常见。在这个过程中,依赖被作为参数注入到构造函数中。请参阅下面的示例。 创建一个名为 GuiceTester 的 Java 类。 GuiceTester.java 输出 编译并运行该文件,您将看到以下输出。

  • 注入是将依赖注入对象的过程。 构造函数注入很常见。 在此过程中,依赖项作为参数注入构造函数。 请参阅下面的示例。 创建一个名为GuiceTester的java类。 GuiceTester.java import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Inj