**大家好,**我目前在做一个缓存应用,遇到以下情况:DAO函数返回一个Flow,表示本地数据库的数据流。在仓库中,我从DAO函数收集数据,在ViewModel中,我从仓库函数收集数据。
我想讨论一下从存储库和ViewModel收集数据的最佳实践。在两个地方收集数据被认为是一个好的实践吗?这种方法是否有任何潜在的缺点或问题?
为了提供更多信息,本地数据库充当应用程序的“真实数据源”,主要数据处理发生在那里。由于DAO函数返回Flow,repository函数返回Flow,因此似乎有必要从存储库中的DAO函数收集数据以观察数据库的更新。
我将非常感谢您的建议,以及关于在考虑使用协程和流时从存储库和ViewModel收集数据的最佳实践的经验。
道:
@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))
}
}
}
}
}
}
型
MovieScreenView模型:
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。
1条答案
按热度按时间8yoxcaq71#
我也是Android开发的新手,但根据Android的一般指导方针,你应该在你的视图模型中使用如下内容:
字符串
并使用这些实时数据来更新您的UI
asLiveData操作符将Flow转换为具有可配置超时的LiveData。就像liveData构建器一样,超时将帮助Flow重新启动。如果另一个屏幕在超时之前观察到,Flow不会被取消。