首页 > 解决方案 > Dagger 2 组件保留旧参考

问题描述

背景

我在应用程序中有多个匕首范围

问题

我正在尝试更新用户对象,UserScope但不知何故,对象更新并没有反映在它的依赖组件上。因此,一旦更新屏幕更新了用户对象,并且 backstack 中的活动接收到更新事件,我想在我的 dagger 依赖项中反映该更新。我试图将内部的现有组件设为空,UserManager但看起来依赖组件仍然持有它的引用。

概括

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

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

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

问题

核心组件

@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
    }
}

标签: kotlindagger-2

解决方案


如果您有组件A -> B -> C并决定交换BB*那么您还需要摆脱由/使用创建的任何对象B或依赖于的任何对象B,因此任何子组件、组件依赖项、对象等。

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

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


推荐阅读