android 在Jetpack Compose和Dagger-Hilt中,两个ViewModel之一未使用来自同一存储库的StateFlow数据进行更新的问题

nbnkbykc  于 12个月前  发布在  Android
关注(0)|答案(2)|浏览(136)

我正在开发一个Jetpack Compose应用程序,并使用Dagger-Hilt进行依赖注入。我有两个ViewModel(MainViewModel和FormViewModel)从单个AppRepository订阅StateFlow。两个ViewModel都正确初始化,但只有MainViewModel从存储库接收更新,而FormViewModel没有。两个示例都是在相同的组合和时间创建的。
备注:这个应用程序是我使用Jetpack Compose和MVVM模式开发的最广泛的应用程序。(目前约800行),并仍在扩大。值得注意的是,此ViewModel的很大一部分(大约一半)是专门用于处理表单的。我的目标是将这些与表单相关的代码重构为一个单独的ViewModel,我不确定这种方法是否符合使用MVVM和Dagger-Hilt的最佳实践。维护一个单一的大型ViewModel是明智的,还是可以接受将功能拆分为多个ViewModel以获得更好的模块化和可维护性?

AppRepository(摘要):

@Singleton
class AppRepository @Inject constructor(...) {
    private val _services = MutableStateFlow<List<LocalService>>(listOf())
    val services: StateFlow<List<LocalService>> = _services
..
}

字符串
主视图模型:

@HiltViewModel
class MainViewModel @Inject constructor(
    private val appRepository: AppRepository,
    private val application: Application
) : ViewModel() {
    val services: StateFlow<List<LocalService>> = appRepository.services

    init {
        viewModelScope.launch {
            services.collect { ... // Logs to print services.size
            }
        }
    }
}


FormViewModel:

@HiltViewModel
class FormViewModel @Inject constructor(private val appRepository: AppRepository) : ViewModel() {
    val services: StateFlow<List<LocalService>> = appRepository.services

    init {
        viewModelScope.launch {
            services.collect { ... // Logs to print services.size
            }
        }
    }
}


模块:

@Module
@InstallIn(SingletonComponent::class)
object Module {
...
@Provides
    fun provideMainRepository(
        ...
    ): AppRepository {
        return AppRepository(
          ...
        )
    }

2023-11-14 11:31:16.170 15406-15406 FormViewModel           com.conecta                  D  MainViewModel init
2023-11-14 11:31:16.172 15406-15406 FormViewModel           com.conecta                  D  MainViewModel formQuestionCrossRef has changed: 0
2023-11-14 11:31:16.173 15406-15406 FormViewModel           com.conecta                  D  MainViewModel serviceFormCrossRef has changed: 0
2023-11-14 11:31:16.174 15406-15406 FormViewModel           com.conecta                  D  MainViewModel services has changed: 0
2023-11-14 11:31:16.757 15406-15406 FormViewModel           com.conecta                  D  FormViewModel init
2023-11-14 11:31:16.758 15406-15406 FormViewModel           com.conecta                  D  FormViewModel formQuestionCrossRef has changed: 0
2023-11-14 11:31:16.759 15406-15406 FormViewModel           com.conecta                  D  FormViewModel serviceFormCrossRef has changed: 0
2023-11-14 11:31:16.760 15406-15406 FormViewModel           com.conecta                  D  FormViewModel services has changed: 0
2023-11-14 11:31:20.028 15406-15406 FormViewModel           com.conecta                  D  MainViewModel services has changed: 30
2023-11-14 11:31:20.270 15406-15406 FormViewModel           com.conecta                  D  MainViewModel formQuestionCrossRef has changed: 1260
2023-11-14 11:31:20.274 15406-15406 FormViewModel           com.conecta                  D  MainViewModel serviceFormCrossRef has changed: 90

n9vozmp4

n9vozmp41#

你不需要在模块中为AppRepository使用@Provides方法。这样,dagger就有两种方法来创建AppRepository的示例--它的@Inject注解构造函数和@Provides方法。老实说,我不确定最后哪种方法会赢,但我很确定问题是你有多个仓库示例。
此外,安装在SingletonComponent中的模块中的@Provides方法并不意味着dagger将只创建该类的一个示例。为此,您必须使用@Singleton注解方法本身。从docs
警告:一个常见的误解是,在模块中声明的所有绑定都将作用于安装该模块的组件。然而,这不是真的。只有用范围注解注解的绑定声明才是作用域。
这意味着有两种可能的解决方案:
1.删除@Provides fun provideMainRepository()
1.从AppRepository中删除@Inject@Singleton,并将@Singleton添加到provideMainRepository()

x759pob2

x759pob22#

关于应用程序架构-你可能需要一个Domain layer。它将允许你:

  • 避免使用大型ViewModel并提高可读性
  • 封装复杂的业务逻辑
  • 提高可测试性
  • 具有可由多个ViewModel重用的业务逻辑

相关问题