kotlin - Dagger 2 组件保留旧参考
问题描述
背景
我在应用程序中有多个匕首范围
- UserScope - 代表用户会话的范围
- ActivityScope - 每个活动的范围
- UserComponent - CoreComponent 的子组件
- UserManager - 创建 UserComponent 的单例
- HomeComponent - 依赖于 UserComponent 的组件
问题
我正在尝试更新用户对象,UserScope
但不知何故,对象更新并没有反映在它的依赖组件上。因此,一旦更新屏幕更新了用户对象,并且 backstack 中的活动接收到更新事件,我想在我的 dagger 依赖项中反映该更新。我试图将内部的现有组件设为空,UserManager
但看起来依赖组件仍然持有它的引用。
概括
用户登录并打开主屏幕。此时我的用户管理器已经使用从 API 调用获得的用户对象创建了用户组件。
主屏幕打开更新屏幕,通过重新创建新的
userComponent
内部更新用户UserManager
。这也会触发一个事件,告诉主屏幕获取更新的用户对象。主屏幕接收事件。但是,HomeViewModel(Screen in backstack) 仍然指的
User
是 dagger 注入的旧对象。
问题
- 这是因为
HomeComponent
它是一个独立的组件吗?那么,它保留了旧的参考吗? - 有没有办法实现这个更新?
- 最好不使用
SubComponent
. 因为我正在使用多模块(动态功能)设置,如果我将其视为一个单独的组件,它会对我有所帮助。
- 最好不使用
核心组件
@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*
那么您还需要摆脱由/使用创建的任何对象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)。
推荐阅读
- mysql - 迁移 - 如何向已填充的表添加 UNIQUE 约束?
- javascript - 如何解决此 Firebase 云功能错误:无法读取属性
- java - 使用字符串和双精度的关系创建树
- android - 无法在分离视图上启动此动画器
- matlab - 获取日期范围内独特季度列表的更快方法
- c++ - 内部类的未解析外部符号
- gradle - Gradle 未将 SNAPSHOT 解析为时间戳
- python - 如何将 curl POST 转换为 Python 中的请求 POST?
- html - 在 CSS 中使用 Flexbox/Grid,使图像在移动设备上堆叠
- ruby-on-rails - 部分控制器 - 如何?