使用协程和 Flow 时从 Repository 和 ViewModel 收集数据

问题描述 投票:0回答:1

大家好 我目前正在开发一个缓存应用程序,遇到以下情况:DAO 函数返回一个 Flow,表示来自本地数据库的数据流。在存储库中,我从 DAO 函数收集数据,在 ViewModel 中,我从存储库函数收集数据。

我想讨论从存储库和 ViewModel 收集数据的最佳实践。在两个地方收集数据是否被认为是一个好的做法?这种方法有任何潜在的缺点或问题吗?

为了提供更多信息,本地数据库充当应用程序的“事实来源”,并且主要数据处理发生在那里。由于 DAO 函数返回 Flow 并且存储库函数返回 Flow,因此似乎有必要从存储库中的 DAO 函数收集数据以观察数据库的更新。 我非常感谢您关于从存储库和 ViewModel 收集数据的最佳实践的建议和经验,同时考虑使用协程和 Flow。

道:

@Dao interface MovieDao { @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun saveMovies(moviesEntity: MoviesEntity) @Query("SELECT * FROM movies") fun getMovies(): Flow<List<MoviesEntity>>? @Query("DELETE FROM movies") suspend fun clearMoviesListing() }

接口MovieRepository:

interface MovieRepository { fun getMoviesResult( category: String, fetchFromRemote: Boolean, ): Flow<Resource<List<Movies>>> }

MovieRepositoryImpl:

@RequiresExtension(extension = Build.VERSION_CODES.S, version = 7) class MovieRepositoryImpl( private val movieApi: MovieApi, private val movieDao: MovieDao ) : MovieRepository { override fun getMoviesResult( category: String, fetchFromRemote: Boolean ): Flow<Resource<List<Movies>>> { return flow { while (true) { emit(Resource.Loading(true)) movieDao.getMovies()?.collect { localListing -> if (localListing.isNotEmpty() && !fetchFromRemote) { emit(Resource.Loading(false)) emit( Resource.Success(data = localListing.map { it.toMovies() }) ) } else { val remoteListing = try { movieApi.getMovies(category = category) } catch (e: IOException) { e.printStackTrace() emit(Resource.Error("Couldn't Reach Server, Check Your Internet Connection, Try Refresh")) null } catch (e: HttpException) { e.printStackTrace() emit(Resource.Error("Couldn't Reach Server, Check Your Internet Connection.")) null } if (remoteListing !== null) { emit(Resource.Loading(false)) remoteListing.let { movie -> movieDao.clearMoviesListing() movieDao.saveMovies(movie.toMoviesEntity()) movieDao.getMovies()!!.collect() { movieEntity -> emit( Resource.Success(data = movieEntity.map { it.toMovies() }) ) } } } emit(Resource.Error(message = "")) emit(Resource.Loading(false)) } } } } } }

电影屏幕视图模型:

private fun getMovieResult(category: String, fetchFromRemote: Boolean) { viewModelScope.launch { movieRepository.getMoviesResult(category, fetchFromRemote) .collect { results -> when (results) { is Resource.Success -> { results.data?.let { result -> state = state.copy(movies = result) } } is Resource.Error -> state = state.copy( error = results.message ?: "An unexpected error occurred" ) is Resource.Loading -> state = state.copy(isLoading = results.isLoading) } } } }

感谢您的宝贵意见!

我不确定在 ViewModel 中再次收集数据是否合适,或者是否有更有效的方法。我想确保我遵循最佳实践并在我的应用程序中充分利用协程和 Flow。

android kotlin caching android-room coroutine
1个回答
0
投票

lateinit var movieListLiveData: MutableLiveData<List<Movies>> private fun getMovieResult(category: String, fetchFromRemote: Boolean) { movieListLiveData = movieRepository.getMoviesResult(category, fetchFromRemote).asLiveData() }

并使用实时数据来更新您的 UI 

asLiveData 运算符将 Flow 转换为具有可配置超时的 LiveData。 就像 liveData 构建器一样,超时将帮助 Flow 在重新启动后幸存下来。如果在超时之前有另一个屏幕观察,则流程不会被取消。

© www.soinside.com 2019 - 2024. All rights reserved.