RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1141446
Accepted
Александр Инженер
Александр Инженер
Asked:2020-06-16 02:19:22 +0000 UTC2020-06-16 02:19:22 +0000 UTC 2020-06-16 02:19:22 +0000 UTC

Android LiveData MVVM 返回发射并使用 DAO 添加到数据库

  • 772

在 ViewModel 内部,使用改造,我以标准方式获取数据

fun getUsers() = liveData(Dispatchers.IO) {
    emit(Resource.loading(data = null))
    try {
        emit(Resource.success(data = nalRepository.getNal()))
    } catch (exception: Exception) {
        emit(Resource.error(data = null, message = exception.message ?: "Error      Occurred!"))
    }
}

是否可以在将这些数据返回到 liveData 之前将其保存到数据库中

private val db = AppDatabase.getInstance(getApplication())
private val dao = db!!.CurrencyDao()
private val service = Executors.newFixedThreadPool(1)

fun addListBook(list: List<Currency>)
{
    service.submit {
        dao.insertList(list)
    }
   service.shutdown()
}

我addListBook()在订阅 liveData 时已经保存在 Fragment 中,但是直接在 ViewModel 中执行会更合乎逻辑,但不清楚如何爬emit(Resource.success(data = nalRepository.getNal()))取并将其发送到数据库。也就是说,它不起作用

 //Получить данные
 var list = emit(Resource.success(data = nalRepository.getNal()))
 //Сохранить в базу
 addListBook(list)
android
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. danilshik
    2020-06-16T18:14:53Z2020-06-16T18:14:53Z

    我使用类似这样的架构:

    视图模型

    class AlbumListViewModel @Inject constructor(private val repository: AlbumRepository): ViewModel(){
        private var query = mutableLiveData("")
        private var albums : LiveData<Result<List<Album>>> = Transformations.switchMap(query, ::getAlbumsBySearch)
    
        private fun getAlbumsBySearch(searchQuery: String): LiveData<Result<List<Album>>>{
            return repository.getAlbumsBySearch(searchQuery)
        }
        fun handleSearchQuery(text: String?) {
            query.value = text
            Log.d("AlbumListViewModel SV", text.toString())
        }
    }
    

    存储库

    class AlbumRepository @Inject constructor(private val remoteSource: AlbumRemoteDataSource, private val database: AppDatabase){
    
        fun getAlbumsBySearch(searchQuery: String): LiveData<Result<List<Album>>>{
    
    
            Log.d("RepositoryNew", searchQuery)
            val resultLiveData = resultLiveData(
                databaseQuery = {database.getAlbumDao().getAlbumsBySearch("%${searchQuery}%")},
                networkCall = {remoteSource.getAlbumsBySearch(searchQuery)},
                saveCallResult = {database.getAlbumDao().insertAll(it.results)}
            )
            Log.d("AlbumRepository", resultLiveData.value.toString())
            return resultLiveData
        }
    
    
    }
    

    远程存储库

    class AlbumRemoteDataSource @Inject constructor(
        private val apiService: APIService
    ): BaseDataSource(){
        suspend fun getAlbumsBySearch(searchQuery: String): Result<BaseResponse<Album>>{
            val result = getResult{apiService.getAlbumsBySearch(searchQuery)}
            Log.d("AlbumRemoteDataSource", result.toString())
            return result
        }
    
    
    }
    

    得到结果

    suspend fun <T> getResult(call : suspend () -> Response<T>) : Result<T>{
            return try {
                //Получаем ответ от вызова
                val response = call()
                if(response.isSuccessful) {
                    //тело
                    val body = response.body()
                    if (body != null)
                        return Result.success(body)
                }
                error("${response.code()} ${response.message()} ${response.errorBody()}")
            } catch (e: Exception){
                Log.d("BaseDataSource", e.toString())
                Result.error(e.message ?: e.toString())
            }
        }
    

    API服务

    interface APIService{
        /**
         * Поиск album по любым параметрам с поиковым запросом "jack-johnson
         * https://itunes.apple.com/search?term=jack+johnson&entity=album
         */
        @GET("search")
        suspend fun getAlbumsBySearch(
            @Query("term") searchQuery: String,
            @Query("entity") typeEntity: String = "album") : Response<BaseResponse<Album>>
    

    LiveData 扩展

    fun <T, A> resultLiveData(
        databaseQuery: () -> LiveData<T>,
        networkCall: suspend () -> Result<A>,
        saveCallResult: suspend (A) -> Unit): LiveData<Result<T>> =
    
        liveData(Dispatchers.IO){
                emit(Result.loading())
                val responseSource = networkCall.invoke()
                Log.d("ResultLiveData Network", responseSource.toString())
                if(responseSource.status == Result.Status.SUCCESS) {
                    saveCallResult(responseSource.data!!)
                    Log.d("resultLiveData", "save database")
                }
                else if(responseSource.status == Result.Status.ERROR){
                    emit(Result.error(responseSource.error))
                    Log.d("resultLiveData", "error ${responseSource.error}")
                }
                val databaseSource = databaseQuery.invoke()
                emitSource(databaseSource.map { Result.success(it) })
            }
    
    fun <T> mutableLiveData(defaultValue: T? = null): MutableLiveData<T>{
        val data = MutableLiveData<T>()
    
        if(defaultValue != null){
            data.value = defaultValue
        }
    
        return data
    }
    

    类 - 包装器

    data class Result<out T>(
        val status : Status,
        val data: T?,
        val error: String?
    ){
        enum class Status{
            SUCCESS,
            LOADING,
            ERROR
        }
    
        companion object{
            fun <T> success(data: T) : Result<T> = Result(Status.SUCCESS, data, null)
            fun <T> error(error: String?, data: T? = null): Result<T> = Result(Status.ERROR, data, error)
            fun <T> loading(data: T? = null): Result<T> = Result(Status.LOADING, data, null)
        }
    
    }
    

    其实有很多用例:

    1. 向存储库发出请求,存储库将保存到数据库中,如果数据发生变化,数据将从数据库通过 LiveData 到达
    2. 发出纯请求并期望在相同的响应中得到结果,中间保存。
    3. 好吧,还是这个选项。

    即使在这个版本中,也有很多方法。例如,您可以先从数据库中进行选择,使缓存的数据可见,然后仅发出请求,将更新的数据插入数据库,并由 LiveData 更新。

    您可以将插入和删除旧数据合并到一个事务中。

    很多用例。

    我们可能应该争取清洁架构。据她介绍,所有应用程序都应该分层。不应该依赖于数据库和外部服务,因此您需要添加 2 个以上的抽象级别(例如 LocalRepository (db) 和 RemoteRepository(外部服务)

    • 2
  2. Best Answer
    Sergei Buvaka
    2020-06-16T12:12:24Z2020-06-16T12:12:24Z

    如果我正确理解您的问题,那么Transformation. 这是一个例子:

    private fun madLiveData(): LiveData<Int> { 
        return Transformations.map(dao.getLiveDataModel()) { model: Model ->
            doSomething(model) model.id } 
    } 
    
    private fun doSomething(Model: Model) {
         //Здесь сохраняйте в бд
    }
    

    PS。我被你的 liveData 弄糊涂了——我以为它是一个返回类型,但现在我意识到这是 coroutineScope 的名称。

    那么你应该以不同的方式做事。

    你可以写这样的东西

    sealed class Result<out T> {
        object Loading: Result<Nothing>()
        data class Success<out T>(val data: T) : Result<T>()
        data class Error(val exception: Exception) : Result<Nothing>()
    } 
    

    一般来说,您可以在这里删除泛型并替换您自己的类型,这样会更容易,但这种解决方案是通用的。

    在您从改造中获得响应的地方,您可以执行以下操作:

    override suspend fun get(args: ArgumentsWrapper?): Result<MODEL> {
            return try {
                val result = parseResponse(getResponse(args))
                Result.Success(result)
            } catch (e: Exception) {
                Result.Error(e)
            }
        }
    
    
    private fun parseResponse(response: Response<RESPONSE>): RESPONSE {
            val data: RESPONSE?
    
            if (response.isSuccessful)
                data = response.body()
            else
                throw getNetworkException(response) // это кастомный метод для генерации ошибки сервера в мой класс, можете тут бросать то что удобно будет вам. 
    
            if (data != null)
                return data
            else
                throw NetworkException(statusMessage = "Generated Network Error Something went wrong") // это кастомный Exception, вы тут можете вернуть либо свой либо один из готовых
        }
    

    因此,在 ViewModel 中,您将已经收到错误或成功的结果。在 ViewModel 中你像这样处理它

    fun getUsers() {
            liveData.launch {
                when (val result = dataSource.get()) {
                    is Result.Success -> doSomethingWithData(result.data)
                    is Result.Error -> handleError(result.exception)
                }
            }
        }
    
    • 0

相关问题

  • 来自片段的列表落后于 BottomNavigationView

  • 无法将变量从 Activity 传递到 Fragment

  • 构建与完成的片段略有不同的片段的最佳方法是什么?

  • 如何更改来自服务器的响应中的日期格式?

  • 谷歌地图在应用程序的发布版本中不起作用

  • 材料设计按钮。单击按钮上的可选区域!

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何从列表中打印最大元素(str 类型)的长度?

    • 2 个回答
  • Marko Smith

    如何在 PyQT5 中清除 QFrame 的内容

    • 1 个回答
  • Marko Smith

    如何将具有特定字符的字符串拆分为两个不同的列表?

    • 2 个回答
  • Marko Smith

    导航栏活动元素

    • 1 个回答
  • Marko Smith

    是否可以将文本放入数组中?[关闭]

    • 1 个回答
  • Marko Smith

    如何一次用多个分隔符拆分字符串?

    • 1 个回答
  • Marko Smith

    如何通过 ClassPath 创建 InputStream?

    • 2 个回答
  • Marko Smith

    在一个查询中连接多个表

    • 1 个回答
  • Marko Smith

    对列表列表中的所有值求和

    • 3 个回答
  • Marko Smith

    如何对齐 string.Format 中的列?

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5