kotlin 使用协程和流时从存储库和ViewModel收集数据

lrpiutwd  于 11个月前  发布在  Kotlin
关注(0)|答案(1)|浏览(148)

**大家好,**我目前在做一个缓存应用,遇到以下情况: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。

8yoxcaq7

8yoxcaq71#

我也是Android开发的新手,但根据Android的一般指导方针,你应该在你的视图模型中使用如下内容:

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重新启动。如果另一个屏幕在超时之前观察到,Flow不会被取消。

相关问题