Dagger 2 组件保留旧参考

Dagger 2 component keeping old reference

背景

我在应用程序中有多个匕首瞄准镜

问题

我正在尝试更新 UserScope 下的用户对象,但不知何故对象更新没有反映在它的依赖组件上。因此,一旦更新屏幕更新了用户对象,并且 backstack 中的 activity 接收到更新事件,我想在我的匕首依赖项中反映该更新。 我试图使 UserManager 中的现有组件无效,但看起来依赖组件仍然保留它的引用。

总结

  1. 用户登录并打开主屏幕。此时我的用户管理器已经使用从 API 调用获得的用户对象创建了用户组件。

  2. 主屏幕打开更新屏幕,通过在 UserManager 中重新创建新的 userComponent 来更新用户。这也会触发一个事件,告诉主屏幕获取更新的用户对象。

  3. 主屏幕收到事件。但是,HomeViewModel(Screen in backstack) 仍然指代由匕首注入的旧 User 对象。

问题

核心组件

@Singleton
@Component
interface CoreComponent {

    val userBuilder: UserComponent.Builder

    val userManager: UserManager

    fun providerContext(): Context

    fun inject(activity: UserActivity)

    @Component.Factory
    interface Factory {
        fun create(
            @BindsInstance applicationContext: Context
        ): CoreComponent
    }
}

用户组件

@UserScope
@Subcomponent
interface UserComponent {

    val userManager: UserManager

    @UserScope
    val user: User

    @Subcomponent.Builder
    interface Builder {

        fun bindUser(@BindsInstance user: User): Builder
        fun build(): UserComponent
    }
}

用户管理器

@Singleton
class UserManager @Inject constructor(private val userBuilder: UserComponent.Builder) {

    var userComponent: UserComponent? = null
        private set

    init {
        // creating as a dummy reference
        createUser(User("1", "1"))
    }

    fun createUser(user: User) {
        userComponent = null
        userComponent = userBuilder.bindUser(user).build()
    }

    fun logout() {
        userComponent = null
    }
}

主页组件

@Component(
    modules = [HomeModule::class],
    dependencies = [UserComponent::class]
)
@ActivityScope
interface HomeComponent {

    fun inject(activity: HomeActivity)

    @Component.Factory
    interface Factory {
        fun create(
            @BindsInstance applicationContext: HomeActivity,
            coreComponent: UserComponent,
        ): HomeComponent
    }
}

家庭模块

@Module
class HomeModule {

    @ActivityScope
    @Provides
    fun provideVM(activity: HomeActivity, user: User): HomeViewModel {
        val vm by activity.scopedComponent {
            HomeViewModel(user)
        }
        return vm
    }
}

如果您有组件 A -> B -> C 并决定将 B 换成 B* 那么您还需要删除创建的所有对象 by/using B 或依赖于 B 的任何东西,因此任何子组件、组件依赖项、对象等

在此示例中,您还需要重新创建 C(这次使用 B*)以获得 C*(使用新的依赖项)。现在您有了新组件 A -> B* -> C*,但是使用 B/C 创建的代码 (Activity/Fragment/ViewModel) 也需要“更新”。由于以后“更新”依赖项是不可行的,因此最简单的方法是重新创建所有依赖项,这次使用 B*/C* 进行注入。

例如 在我允许在用户之间切换的一个应用程序中,我有我的主要 Activity“Singleton -> Activity”范围,引用用户管理器并显示开关 UI。实际的应用程序内容(每个用户)包含在 UserFragment 中,每当用户更改时我都会将其作为一个整体替换,因为此片段(以及其中的所有 UI)是 Singleton -> Activity -> User -> Fragment范围。
由于包括用户管理器在内的 Singleton 不会更改,因此我不必重新创建 Activity,因此我需要做的就是重新创建受影响的部分(在我的例子中是 Fragment)。