Android 中的 Dagger2 子组件混淆

Dagger2 sub-component confusion in Android

我的目标:

了解范围的工作原理以及如何实施 UserScope 我可以在多个 Activity 上使用并根据需要 reset/create 一个新的 Activity。

我使用的方法:

  1. 此博客:http://frogermcs.github.io/building-userscope-with-dagger2/
    它显然解释了我在这里试图实现的同一件事。

  2. 官方文档 http://frogermcs.github.io/building-userscope-with-dagger2/

博客快速简介

显然,有UserModuleUserComponent。作者已将 UserComponent 的创建包装在 UserManager 下,后者具有 ApplicationScope。所以 UserManager 在登录时可用。当登录成功时 UserComponent 通过 UserManager 初始化。简单的逻辑。

现在,这个已经初始化的 @UserScope 被用于几个 Activity,如图所示。

我很难理解

看看UserComponent

public interface UserComponent {

    @Subcomponent.Builder
    interface Builder {
        Builder sessionModule(UserModule userModule);

        UserComponent build();
    }

    UserDetailsActivityComponent plus(UserDetailsActivityComponent.UserDetailsActivityModule module);

    RepositoriesListActivityComponent plus(RepositoriesListActivityComponent.RepositoriesListActivityModule module);

    LogoutManager logoutManager();
}

具体来说UserDetailsActivityComponentRepositoriesListActivityComponent是通过UserComponent创建的。像这样,

@Override
    protected void onUserComponentSetup(UserComponent userComponent) {
        userComponent.plus(new UserDetailsActivityComponent.UserDetailsActivityModule(this)).inject(this);
    }

所以它们首先在 UserComponentUserManager 中预先创建,然后它调用 onUserComponentSetup,然后创建适当的组件并注入当前的 Activity。

我无法理解上面提到的这种模式, 正如我在文档中读到的那样,当我们需要在特定实例上注入时,我们使用 plus(InjectionToBeDoneOn i) InjectionToBeDoneOn。但是为什么要通过这个组件注入这个 Activity 呢?这有什么用呢?用 DaggerXYZComponent().Builder().Build().inject(activity) 和 activity 的 onCreate() 中的传统方式来做这件事难道没有意义吗?

此外,我缺少体面的 material UserScope 在 Android 中的实现方式,它具有从登录到注销的生命周期,但不大于 @Singleton范围。

we use plus(InjectionToBeDoneOn i) when we need the injection on particular instance of InjectionToBeDoneOn

不完全是。一个组件基本上有3种方法

  1. SomeDependency provideDependency() 只是创建/提供对子组件的一些依赖性,或者用于手动检索(基本上是 getter)
  2. void inject(MyAndroidFrameworkClass object) 注入对象及其依赖项
  3. SomeSubComponent plus(SubComponentModule module) 创建一个子组件,添加额外的模块

你在这里混淆了 2. 和 3.。

// user scoped component
userComponent
    // create a subcomponent (UserDetailsActivityComponent)
    .plus(new UserDetailsActivityComponent.UserDetailsActivityModule(this))
    // use the UserDetailsActivityComponent that was just created and inject with it
   .inject(this);

UserDetailsActivityComponentUserComponent 的子组件,这就是扩展 userComponent .plus(somemodule) 以创建子组件的原因。如果您的子组件不需要额外的模块,您也可以只使用 .plus() 因为对于 Dagger 来说重要的是 return 类型 或一般的签名。

  • 如果它 return 是另一个组件,则它会创建一个子组件。
  • 如果它有一个参数和returns void或者参数类型,那么它是一个注入方法
  • 如果它没有参数,并且 returns 某些类型是提供方法 (1.) 来公开某些依赖项

but why inject this Activity via this Component? What does this accomplish?

如果您要从头开始创建 UserDetailsActivityComponent,它只会看到并知道它可以提供什么 本身 。如果你在某处有一些 @Singleton 它无法访问其中的任何一个,因为它不是对象图的一部分。

一个子组件扩展另一个组件,添加到对象图中。如果你有一个 @Singleton A 并且你的 UserComponentn 需要 A 来提供 B,有一个子组件这将起作用,没有它你将得到一个 cannot be provided错误。

匕首不是魔法。它实际上只是建立一个有向图并检查是否一切正常。如果某些依赖关系彼此之间存在循环依赖关系,或者如果图形的某些部分无法访问它需要的依赖关系,它将抱怨。

您的 UserComponent 持有您的用户数据。为简单起见,假设它持有 UserName。现在 UserDetailsActivity 可能想显示 UserName,但它需要一些方法才能得到它。

通过使用 @Singleton AppComponent 作为父级,您可以访问某些 API,但不能访问用户范围的 API。您可以将用户范围的对象移动到 @Singleton AppComponent 中,但是每次用户更改时您都必须重新创建 AppComponent(这违背了声明它的目的 @Singleton ,否则您必须找到其他方法来更新/更改用户。

如果你想用 Dagger 的方式来做,你可以创建一个 UserComponent 来 adds User 到图表中。这样子组件就可以访问它并执行它们的用户操作。

当用户发生变化时,您必须确保销毁所有使用 UserComponent 的活动/片段,然后您只需重新创建所有内容 — 使用新用户。

wont it make sense to do in conventional way in OnCreate() of the activity with DaggerXYZComponent().Builder().Build().inject(activity)

当然可以。作者只是将对 app.getAppcomponent().getUserManager().getUserComponent() 或类似内容的调用放入他们的 BaseActivityBaseUserActivity 中,这样您就不必每次都重复相同的代码行。 onCreate基本还是会调用这个方法,只是让你直接使用组件,不用每次都去取组件。
您显然可以删除那些模板方法并内联 onCreate 中的所有内容,从而导致重复代码,使长 运行.

中的维护变得更加困难

i am missing decent material of how UserScope is implemented in android which has life span from log-in to log-out but not bigger than @SingleTon scope.

Android 无济于事,自己清理是你的工作。如果用户更改,您将清除 UserComponent 及其 SubComponents 接触的所有内容,并使用新用户重新创建它。

您必须将 UserComponent 与当前用户一起存储在应用程序 class 中,一些 "real" 单例,或一些 "Manager" 在具有 [=21] 的应用程序组件中=] 范围。我想每种方法都有自己的好处。

Scopes 只是向 Dagger 指出一个对象应该只存在于一个 Scope 中一次。无论您将其命名为什么,或者作用域中有多少个对象,都无关紧要。 Dagger 只需要它们来确保没有依赖循环。