使用观察到在Kotlin中更新另一个观察的变量

发布于 2025-01-20 10:18:19 字数 1029 浏览 5 评论 0原文

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

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

 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)
        }
    })
}

I am trying first handle the response from API by using observe. Later after observing the handled variable I want to save it to database.

The variable tokenFromApi is updated inside tokenResponseFromApi's observer. Is it possible to observe tokenFromApi outside the observer of tokenResponseFromApi? When debugged, the code did not enter inside tokenFromApi observer when the app started.

 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)
        }
    })
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

合久必婚 2025-01-27 10:18:19

您的问题是您在设置过程中在tokenfromapi上注册观察者,当您获得API响应时,您将替换 tokenfromapi没有在上面注册一个观察者。因此,如果它发出价值,您将永远不会知道。 The only observer you have registered is the one on the discarded tokenFromApi which is never used by anything

Honestly your setup here isn't how you're supposed to use LiveData.与其为每个响应创建一个全新的tokenfromapi,您只需要一个livedata即可观察。当有一个新值(例如API令牌)时,您 set livedata,所有观察者都会看到并对其做出反应。一旦连接,它就完成了,一切都起作用。

您现在的方式是,您有一个需要拆开的数据源,替换为新的数据源,然后与之重新连接 - 每次有新数据,如果您明白了我的意思。

理想情况下,片段是UI,因此对事件有反应(通过观察livedata之类的数据源,并将UI事件推到视图模型(有人单击此内容等)。存储确实属于VM - 您已经在这里调用的VM中使用了一半,对livedata s属于VM,有关VM内部发生的事情以及应用程序的其余部分 - 它们揭示了UI需要反应的信息。 part of your problem


Have a look at the App Architecture guide (that's the UI Layer page but it's worth being familiar with the rest), but this is a basic sketch of how I'd do it:

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
    }
}

so it's basically all contained within the VM - the UI stuff like fragments doesn't need to know anything about API calls ,无论是存储的东西,如何存储。 VM可以在需要发出一些新数据,更新某些状态或其他任何内容时更新其暴露的livedata对象,这对VM之外的事物而不是内部工作很有趣。片段仅观察对其感兴趣的哪一个,并根据需要更新UI。

(我知道回调情况可能比此类情况更复杂,例如保存到数据库可能涉及flow或其他东西。但是,这个想法是相同的 - 在其回调/结果函数中,将值推到您的livedata适当地,因此观察者可以接收它,并且使用livedataflow flow flow 新的tokenentity被推到一个呼叫savetokentodb的观察者,如果这种管道设置是有道理的!关于那些中间步骤

Your problem is that you're registering the observer on tokenFromApi during setup, and when you get your API response, you're replacing tokenFromApi without registering an observer on it. So if it ever emits a value, you'll never know about it. The only observer you have registered is the one on the discarded tokenFromApi which is never used by anything

Honestly your setup here isn't how you're supposed to use LiveData. Instead of creating a whole new tokenFromApi for each response, you'd just have a single LiveData that things can observe. When there's a new value (like an API token) you set that on the LiveData, and all the observers see it and react to it. Once that's wired up, it's done and it all works.

The way you're doing it right now, you have a data source that needs to be taken apart, replaced with a new one, and then everything reconnected to it - every time there's a new piece of data, if you see what I mean.

Ideally the Fragment is the UI, so it reacts to events (by observing a data source like a LiveData and pushes UI events to the view model (someone clicked this thing, etc). That API fetching and DB storing really belongs in the VM - and you're already half doing that with those functions in the VM you're calling here, right? The LiveDatas belong in the VM because they're a source of data about what's going on inside the VM, and the rest of the app - they expose info the UI needs to react to. Having the LiveData instances in your fragment and trying to wire them up when something happens is part of your problem


Have a look at the App Architecture guide (that's the UI Layer page but it's worth being familiar with the rest), but this is a basic sketch of how I'd do it:

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
    }
}

so it's basically all contained within the VM - the UI stuff like fragments doesn't need to know anything about API calls, whether something is being stored, how it's being stored. The VM can update one of its exposed LiveData objects when it needs to emit some new data, update some state, or whatever - stuff that's interesting to things outside the VM, not its internal workings. The Fragment just observes whichever one it's interested in, and updates the UI as required.

(I know the callback situation might be more complex than that, like saving to the DB might involve a Flow or something. But the idea is the same - in its callback/result function, push a value to your LiveData as appropriate so observers can receive it. And there's nothing wrong with using LiveData or Flow objects inside the VM, and wiring those up so a new TokenEntity gets pushed to an observer that calls saveTokenToDb, if that kind of pipeline setup makes sense! But keep that stuff private if the outside world doesn't need to know about those intermediate steps

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文