使用 observe 作为在 Kotlin 的另一个 observe 中更新的变量

Use observe for a variable that updated inside another observe in Kotlin

我正在尝试首先使用 observe 处理来自 API 的响应。稍后在观察处理变量后我想将它保存到数据库中。

变量tokenFromApitokenResponseFromApi的观察者中更新。是否可以在 tokenResponseFromApi 的观察者之外观察 tokenFromApi?调试时,应用程序启动时代码没有进入 tokenFromApi observer。

 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {    
    var tokenResponseFromApi: LiveData<String>? = MutableLiveData<String>()
    var tokenFromApi: LiveData<TokenEntity>? = MutableLiveData<TokenEntity>()

    tokenResponseFromApi?.observe(viewLifecycleOwner, Observer {
                tokenResponseFromApi ->
            if (tokenResponseFromApi != null) {
                tokenFromApi = viewModel.convertTokenResponseToEntity(tokenResponseFromApi, dh.asDate)
            }
        })

    tokenFromApi?.observe(viewLifecycleOwner, Observer {
            tokenFromApi ->
        if (tokenFromApi != null) {
            viewModel.saveTokenToDB(repo, tokenFromApi)
        }
    })
}

您的问题是您在设置期间在 tokenFromApi 上注册了观察者,当您收到 API 响应时,您正在 替换 tokenFromApi 在其上注册一个观察者。所以如果它曾经发出一个值,你永远不会知道它。您注册的唯一观察者是丢弃的 tokenFromApi 上的观察者,它从未被任何东西使用

老实说,您在这里的设置不是您应该使用的方式 LiveData。无需为每个响应创建一个全新的 tokenFromApi,您只需要一个 LiveData,事物可以 观察 。当有一个新值(如 API 令牌)时,您 设置 LiveData 上,所有观察者都会看到它并对其做出反应。一旦连接好,就完成了,一切正常。

你现在的做法是,你有一个数据源需要拆开,用一个新的替换,然后所有的东西都重新连接到它——每次有一个新的数据,如果你明白我的意思了。

理想情况下,片段是 UI,因此它对事件做出反应(通过观察 LiveData 之类的数据源并将 UI 事件推送到视图模型(有人点击了这个东西等)。API 提取和数据库存储确实属于 VM - 你已经在 VM 中使用你在这里调用的那些功能完成了一半,对吧? LiveDatas属于虚拟机,因为它们是关于虚拟机内部发生的事情的数据源,以及应用程序的其余部分——它们公开了 UI 需要做出反应的信息。将 LiveData 个实例放在您的片段并在发生某些事情时尝试将它们连接起来是您问题的一部分


看看 App Architecture guide(这是 UI 层页面,但值得熟悉其余部分),但这是我如何做的基本草图:

class SomeViewModel ViewModel() {

    // private mutable version, public immutable version
    private val _tokenFromApi = MutableLiveData<TokenEntity>()
    val tokenFromApi: LiveData<TokenEntity> get() = _tokenFromApi

    fun callApi() {
        // Do your API call here
        // Whatever callback/observer function you're using, do this
        // with the result:
        result?.let { reponse -> 
                convertTokenResponseToEntity(response, dh.asDate)
            }?.let { token ->
                saveTokenToDb(repo, token)
                _tokenFromApi.setValue(token)
            }
    }

    private fun convertTokenResponseToEntity(response: String, date: Date): TokenEntity? {
        // whatever goes on in here
    }

    private fun saveTokenToDb(repo: Repository, token: TokenEntity) {
        // whatever goes on in here too
    }
}

所以它基本上都包含在 VM 中 - UI 片段之类的东西不需要知道任何关于 API 调用的信息,无论是否正在存储某些东西,它是如何存储的。当 VM 需要发出一些新数据、更新某些状态或其他任何东西时,它可以更新其公开的 LiveData 对象之一 - 对 VM 外部的事物而不是其内部工作感兴趣的东西。片段只是 observe 感兴趣的片段,并根据需要更新 UI。

(我知道回调情况可能比这更复杂,比如保存到数据库可能涉及 Flow 或其他东西。但想法是一样的 - 在它的 callback/result 函数中,适当地将一个值推送到您的 LiveData,以便观察者可以接收到它。在 VM 中使用 LiveDataFlow 对象并连接它们以创建一个新的 [=27] 并没有错=] 被推送给调用 saveTokenToDb 的观察者,如果这种管道设置有意义的话!但是如果外界不需要了解这些中间步骤,请将这些内容保密