8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

LiveData 未在第二次 API 调用时更新其值

Mystus 2月前

37 0

我正在使用 retrofit 和 ViewModel 概念通过 api 调用获取货币汇率。启动应用程序时,我能够从服务器获取最新数据,但是当我尝试更新实时

我正在使用 retrofit 和 ViewModel 概念通过 api 调用获取货币汇率。在启动应用程序时,我能够从服务器获取最新数据,但是当我尝试通过单击按钮来更新实时数据时,实时数据值不会更新,我得到的是相同的旧数据。所以有人可以帮我如何在按钮单击事件上更新实时数据吗?

ViewModel 类*****

类 MainViewModel(私有 val 存储库:CurrencyRepository):ViewModel(){

init {
    viewModelScope.launch() {
        repository.getCurrencyExchangeList()
    }
}

val quotes: LiveData<CurrencyData>
    get() = repository.currencyLiveData

}

存储库类*****

类 CurrencyRepository(private val currencyService:CurrencyInterface){

val currencyLiveData = MutableLiveData<CurrencyData>()


suspend fun getCurrencyExchangeList() {
    val result = currencyService.getAllCurrencyData()
    if (result.body() != null) {
        //currencyLiveData.postValue(result.body())
        currencyLiveData.value = result.body()
    }
}

}

方法(在 MainActivity 中)获取和更新货币列表 *****

私人乐趣 fetchCurrencyRates() {

    val currencyService = RetrofitHelper.getInstance().create(CurrencyInterface::class.java)
    val repository = CurrencyRepository(currencyService)
    val mainViewModel =
        ViewModelProvider(this, MainViewModelFactory(repository))[MainViewModel::class.java]
    mainViewModel.quotes.observe(this, Observer {
        Log.d("AllCurrencyList", it.updated)

    })

}
帖子版权声明 1、本帖标题:LiveData 未在第二次 API 调用时更新其值
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Mystus在本站《kotlin》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 单击按钮时会调用 fetchCurrencyRates 方法吗?如果是,为什么要创建视图模型及其中的所有其他内容?

  • 我正在开发一个应用程序,需要将 json 文档的 zip 存档提取到文件夹中。我遇到的问题是有时存档包含嵌套的 zip 文件。我目前的 c...

    我正在开发一个应用程序,需要将 JSON 文档的 zip 存档提取到文件夹中。我遇到的问题是有时存档包含嵌套的 zip 文件。我当前的代码如下所示:

    fun File.unzipServiceFile(toPath: String): List<File>
        {
            val retFiles = mutableListOf<File>()
            ZipFile(this).use { zipFile ->
                zipFile.entries().asSequence().forEach { zipEntry ->
                    zipFile.getInputStream(zipEntry).use { input ->
                        //if there are nested zip files, we need to extract them
                        if (zipEntry.name.endsWith(".zip")) {
                            //we need to go deeper
                        }
                        else if (zipEntry.name.endsWith(".json") && !zipEntry.isDirectory && !zipEntry.name.startsWith(".") && !zipEntry.name.startsWith(
                                "_"
                            )
                        ) {
                            val file = File("$toPath/${zipEntry.name}")
                            FileUtils.writeByteArrayToFile(file, input.readBytes())
                            retFiles.add(file)
                        }
                    }
                }
            }
    
            return retFiles
        }
    

    我实际上并不想将嵌套的 zip 文件写入文件夹,因为这样我就必须将它们从目录中清除。我只想提取内容,或者如果还有其他嵌套层,则继续递归。你知道我该怎么做吗?

  • 给定一个房间数据库和一个基于 DateTime 的参数的请求:@Transaction@Query(\'SELECT * FROM itemModel WHERE datetime(datetime(`end`), 'localtime') > datetime(:minDate, 'localt...

    给定一个房间数据库和一个基于 DateTime 参数的请求:

    @Transaction
    @Query("SELECT * FROM itemModel WHERE datetime(datetime(`end`), 'localtime') >  datetime(:minDate, 'localtime') ORDER BY `end` ASC")
    fun getFlow(
        minDate: LocalDateTime,
    ): Flow<List<ItemModel>>
    

    => 根据参数 minDate ,从请求返回的数据应该随着时间而改变(即使数据库没有数据变化)

    如何处理流程更新?因为:

    • 数据库端没有任何变化(因此流程永远不会收到变化通知)
    • 只有请求中的日期(应该)会改变,但是一旦流程加载完成,SQL 请求似乎会保留其参数,就像第一次调用时一样。

    我像这样初始化我的流程:

    var items: StateFlow<List<ItemModel>>
    fun initItemsFlow(context: Context) {
        items = getAllRecords(context).stateIn(
            scope = coroutineScope,
            started = SharingStarted.WhileSubscribed(5_000),
            initialValue = emptyList(),
        )
    }
    

    我是否应该手动 initItemsFlow 再次调用(=从头开始重新设置整个流程)或者是否有更好的流程/房间机制来处理这个问题?

    谢谢

  • Pa_ 2月前 0 只看Ta
    引用 5

    您可以 File 使用实例来 ZipFile 使用的实例来 InputStream 解压缩的内容 ZipInputStream

    zipFile.getInputStream(zipEntry).use { input ->
        //if there are nested zip files, we need to extract them
        if (zipEntry.name.endsWith(".zip")) {
            ZipInputStream(input).use { zipStream ->
                val nestedZipEntry: ZipEntry = zipStream.nextEntry
                // ...
            }
        } else if ...
    }
    

    如果您需要从 ZipInputStream 解压缩的更多帮助,请参见此处: 如何使用 InputStream 从 ZIP 读取文件?

  • 我不知道这是否只是由复制粘贴错误引起的,但 dao getFlow 需要一个 LocalDateTime 参数,而在(我猜)视图模型中,您只能 getAllRecords 使用 Context 参数进行调用。不清楚这些函数是如何关联的,因此在我的回答的其余部分中,我将忽略它, getAllRecords 因为它似乎没有任何与当前问题相关的用途。

    相反,我将概述如何更改 getFlow minDate 参数,同时仍返回相同的 StateFlow。然后您可以根据实际代码进行调整。

    解决方案是引入另一个流 - MutableStateFlow - 来存储 minDate。MutableStateFlow 就像一个变量,它表示一个可以更改的值,因此每当您想要更新 minDate 时,只需设置 MutableStateFlow 的值即可。由于 MutableStateFlow 也是一个流,因此您可以使用任何流转换函数转换其值。在这种情况下,您希望用从中返回的流切换流 getFlow .

    假设您想要在视图模型中公开数据库流并使用它来更新参数, minDate 那么我上面描述的内容可能如下所示:

    class MyViewModel(
        dao: MyDao,
    ) : ViewModel() {
        private val minDate = MutableStateFlow<LocalDateTime?>(null)
    
        val items: StateFlow<List<ItemModel>> = minDate
            .flatMapLatest {
                if (it == null) flowOf(emptyList())
                else dao.getFlow(it)
            }
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(5_000),
                initialValue = emptyList(),
            )
    
        fun updateMinDate(date: LocalDateTime) {
            minDate.value = date
        }
    }
    

    minDate 是新的 MutableStateFlow。它用作属性的基础 items ,并 flatMapLatest 用于根据 minDate 的内容切换到另一个流。 Flow<LocalDateTime> 使用 MutableStateFlow 的值作为参数 Flow<List<ItemModel>> 进行调用, getFlow

    然后,该流将转换为 StateFlow,可供 UI 收集。您应该为此使用, viewModelScope 而不是其他范围。请注意,您不需要在此处切换到 IO 调度程序,这是由 Room 库内部完成的。

    现在,无论何时调用, updateMinDate 流程 items 都会自动更新此新日期。此外,数据库中的任何更改都会导致 StateFlow 更新。这是在不离开流程世界的情况下修改流程的常用方法。

  • 我尝试使用“aux”对象的不同值多次运行以下代码。time <- seq(0, 30, 1)stock <- c(sK=0, sF=1) aux <- c(aH=0.4, aRel=0.5, aRes=0.5, aS=0.8)...

    我尝试使用“aux”对象的不同值多次运行以下代码。

    time <- seq(0, 30, 1)
    stock <- c(sK=0, sF=1) 
    aux <- c(aH=0.4, aRel=0.5, aRes=0.5, aS=0.8)
    
    model <- function(time, stock, aux) {
      with(as.list(c(stock, aux)), { 
        aA <- 1-sK/1  
        fH <- 1*aH*aA
        sF <- fH*aRel*0.2*0.8
        fS <- sF*aRes
        sK <- fS*aS
        net_f <- fH - fS
        net_k <- fS
        return(list(c(net_f, net_k), 
                    fH=fH, fS=fS, aA=aA, net_f=net_f, net_k=net_k))
      })
    }
    
    library(deSolve)
    out <- data.frame(ode(times=time, y=stock, parms=aux, func=model, method='euler'))
    out
    

    我的问题是:

    1. 我已经创建了一个用于网格搜索的数据框
    d <- crossing(aH=seq(0, 1, 0.1), aRel=seq(0, 1, 0.1), aRes=seq(0, 1, 0.1),
                  aS=seq(0, 1, 0.1))
    

    我如何将此网格搜索与上述模型联系起来,并获得“aux”的最佳组合?我意识到网上有关于这个问题的例子,但我的问题是,“aux”是进一步建模代码的值

    out <- data.frame(ode(times=time, y=stock, parms=aux, func=model, method='euler'))
    
    1. 对于行
    sF <- fH*aRel*0.2*0.8
    

    我需要将值 0.2 和 0.8 更改为其他值,例如,0.2 也可以更改为 0.5 或 0.8,而 0.8 也可以更改为 0.5 和 0.2。因此对于这部分,有 3*3=9 种情况。在网格搜索中执行此操作的正确方法是什么?

    希望我已经清楚描述我的问题。请给我一些建议。

  • 我认为它是由预测准确度或由预测模型计算得出的,因为网格搜索通常用于机器学习中的训练和测试

  • 我希望我正确理解了你的问题。如果是这样,我的建议是将这 ode 一行放在一个有参数的函数中 aux 。比如

    test_aux <- function(aux) {
      data.frame(ode(times=time, y=stock, parms=aux, func=model, method='euler'))
    }
    

    然后,对网格中的每一行调用此函数,或者使用 apply() 列出列 dplyr (如果您愿意的话) rowwise()

    model_out <- apply(d, 1, test_aux)
    
    # Or
    
    library(dplyr)
    d %>%
    rowwise() %>%
    mutate(model_out = list(test_aux(c_across(aH, aRel, aRes, aS))))
    

    为了选择“最佳组合”,您应该创建一个输出所需指标的函数,并进行迭代 model_out ,再次使用 lapply() sapply() ,或者使用 mutate() 创建一个具有该指标值的新列。

返回
作者最近主题: