Dagger Hilt 能否感知 Module class 中的变量是否发生变化并更新其值?

Can Dagger Hilt realise whether a variable in a Module class has changed and update its value?

我正在编写一个使用 Firebase Auth 和 DI 的 Android 应用程序。

在这个应用程序中,我经常需要使用用户的 UID 来执行一些数据库操作,为了寻找停止通过 MVVM 层传递 UID 的方法,我决定尝试依赖注入。

我的 AppModule 如下所示:

AppModule.kt

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    @Singleton
    @Provides
    fun provideServer(@ApplicationContext c: Context) = Server(c, Volley.newRequestQueue(c), provideUid())

    @Singleton
    @Provides
    fun provideFirebase() = FirebaseSource(FirebaseAuth.getInstance())

    @Singleton
    @Provides
    fun provideFirebaseAuth() = Firebase.auth

    @Singleton
    @Provides
    fun provideFirebaseUser(): Boolean {
        return provideFirebaseAuth().currentUser != null
    }

    @Singleton
    @Provides
    // FIXME
    fun provideUid(): String {
        return provideFirebaseAuth().currentUser?.uid ?: "" 
    }
}

Function provideUid() returns Firebase 当前用户的 UID,并作为依赖项注入到单独的 Server class:

Server.kt(部分)

class Server @Inject constructor(
    private val c: Context,
    private val volleyRequestQueue: RequestQueue,
    private val uid: String
): IServer {

应用首次启动时,Dagger Hilt 使用此构造函数并提供空 UID,因为此时没有登录用户。此行为在应用程序生命周期的其余部分持续存在,并且 Server class 永远不会有非空 UID,因为它已经使用空 UID 构造为 属性.

重新启动应用程序将构建具有非空 UID 的 Server class,因为 Firebase Auth 会保留一些用户身份验证状态的注册表。

那么我的问题是,Dagger Hilt 是否可以意识到 UID 已更改并更新其值。

我尝试过的事情:

你可以试试:

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    @Provides
    fun provideServer(@ApplicationContext c: Context, queue: RequestQueue, uid: String) = Server(c, queue, uid)

    @Provides
    @Singleton
    fun provideResponseQueue(@ApplicationContext c: Context) = Volley.newRequestQueue(c)

    @Singleton
    @Provides
    fun provideFirebase() = FirebaseSource(FirebaseAuth.getInstance())

    @Singleton
    @Provides
    fun provideFirebaseAuth() = Firebase.auth

    @Singleton
    @Provides
    fun provideFirebaseUser(): Boolean {
        return provideFirebaseAuth().currentUser != null
    }

    @Provides
    // FIXME
    fun provideUid(): String {
        return provideFirebaseAuth().currentUser?.uid ?: "" 
    }
}

如果在应用程序中创建了一次服务器对象的实例,则此解决方案将不起作用。

首先,您很少希望一个 @Provides 方法调用另一个方法。通常最好让 Dagger 为您连接这些方法之间的依赖关系。

Dagger 永远不会重新创建或更新它已经创建的对象。如果您想要一个始终 return 当前 uid 的引用,您可以直接注入 FirebaseAuthProvider<String>.

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    // Consider making a @Singleton @Provides method for RequestQueue.
    // That would let you use the @Inject annotation on Server's constructor.
    @Singleton
    @Provides
    fun provideServer(
        @ApplicationContext c: Context,
        uidProvider: Provider<String>
    ) = Server(c, Volley.newRequestQueue(c), uidProvider)

    @Singleton
    @Provides
    fun provideFirebase() = FirebaseSource(FirebaseAuth.getInstance())

    @Singleton
    @Provides
    fun provideFirebaseAuth() = Firebase.auth

    @Provides
    fun provideFirebaseUser(auth: FirebaseAuth): Boolean {
        return auth.currentUser != null
    }

    // This should not be a singleton.
    // Consider using @Named or a custom qualifier for common types like String.
    @Provides
    fun provideUid(auth: FirebaseAuth): String {
        return auth.currentUser?.uid ?: "" 
    }
}

Can Dagger Hilt realize whether a variable in a Module class has changed and then update its value?

最简单的答案是否定的,不能。

要让 Dagger Hilt 为 FirebaseAuth 提供实例,您只能使用:

@Provides
fun provideFirebaseAuth() = FirebaseAuth.getInstance()

如果你想在另一个方法中使用上面的实例,正如@Nitrodon 已经指出的那样,你应该将该实例作为参数传递给下一个方法并且 not 调用它直接地。所以代码应该是这样的:

@Provides
fun provideFirebaseUser(auth: FirebaseAuth) = auth.currentUser

但是,这没有用,因为根据用户的身份验证状态,currentUser 对象可以为 null。除此之外,当一个对象被创建时,你可以使用它但它不会被重新创建。所以在你的 AppModule class 中添加它没有任何意义。您应该做的是在您的应用程序代码中注入一个 FirebaseAuth 实例,并检查 currentUser 是否为空。如果它不为空,那么您可以安全地使用 UID。

如果您想知道身份验证状态,那么您应该附加一个 AuthStateListener,正如我在以下 post:

的回答中所解释的那样