gpt4 book ai didi

android - 如何使用 Android ViewModel 实现 Arrow Kt?

转载 作者:行者123 更新时间:2023-12-02 13:11:41 28 4
gpt4 key购买 nike

在 Android 中,网络操作通常在 ViewModel 内完成。 .这确保即使 ActivityFragment重新创建(例如,当设备旋转时),网络调用会继续进行并且不会被取消。

现在提交来自 ViewModel 的网络请求的结果到 View ( Activity/Fragment )。您有一个 react 组件,例如 LiveDataObservable设置它的值。像:

val resultLiveData = MutableLiveData<Result>()

fun doNetworkRequest() {
repository.requestSomeResult() // Assume this returns Arrow's IO
.unsafeRunAsync { eitherResult ->
eitherResult.fold({ error ->
// Handle Error
}, { result ->
resultLiveData.value = result
})
}
}

我想知道是否有办法制作 val resultLiveData = MutableLiveData<Result>()不依赖于特定的实现,例如 LiveData类似于返回 higher kind , Kind<F, Result>反而。

有没有办法我可以做:
val result = Kind<F, Result>()

fun doNetworkRequest() {
repository.requestSomeResult() // Assume this returns Arrow's IO
.unsafeRunAsync { eitherResult ->
eitherResult.fold({ error ->
// Handle Error
}, { result ->
resultLiveData.sendValue(result) // Or however it should be done
})
}
}

所以我可以定义 Kind<F, Result>后来有了我想要的实现?

最佳答案

谢谢这个问题!这是我最近一直在做的事情。关于这点需要提几点:

在接下来的几天里,我们将为 Arrow 发布一个 KotlinX 集成模块。我将允许你在 CoroutineScope 中定义你的 IO 任务。 IE:

yourIOTask().unsafeRunScoped(scope) { cb -> }

如果提供的范围被取消,这将确保您的 IO 任务被取消。这意味着您可以将“ View 模型”操作的范围限定为 doNetworkRequest在这个使用 View 模型范围的示例中,您将确保它们能够在配置更改后继续存在,并在 View 模型发布时被取消。

就是说,如果我们目前观察 Android ViewModel 的工作方式,您仍然需要一个“中间层缓存”来交付结果,正如您提到的那样,以确保始终交付这些结果,并且一旦 View 开始观察我得到了最新鲜的数据。通过将这种机制与上一段中提到的范围相结合,您可以确保长期运行的任务将始终交付结果,无论它们是在配置更改之前、期间或之后完成的。

从这个意义上说,如果您想继续在底层使用 Android ViewModel,您可以使用箭头进行编码,例如:
interface ViewStateCache<ViewState> {

val cacheScope: CoroutineScope

fun observeViewState(observer: LifecycleOwner, renderingScope: CoroutineScope, render: (ViewState) -> IO<Unit>): IO<Unit>

fun updateViewState(transform: (ViewState) -> ViewState): IO<ViewState>
}

我们可以使用这个契约来确保以纯粹的方式使用 ViewModel。所有的 ViewModel 都可以实现这个契约,比如:
class ViewModelViewStateCache<ViewState>(initialState: ViewState) : ViewModel(), ViewStateCache<ViewState> {

override val cacheScope: CoroutineScope = viewModelScope

private val _viewState = MutableLiveData<ViewState>(initialState)
private val viewState: LiveData<ViewState> = _viewState

override fun updateViewState(transform: (ViewState) -> ViewState) =
IO {
val transformedState = transform(viewState.value!!)
_viewState.postValue(transformedState)
transformedState
}

override fun observeViewState(observer: LifecycleOwner, renderingScope: CoroutineScope, render: (ViewState) -> IO<Unit>) =
IO {
viewState.observe(observer, Observer<ViewState> { viewState ->
viewState?.let { render(it).unsafeRunScoped(renderingScope) {} }
})
}
}

这样,您就可以有效地拥有一个使用 Android ViewModel 实现的 View 状态缓存。这是一个实现细节,所以你可以注入(inject)它。您的程序将针对接口(interface)工作。

在这里,ViewModel 仅作为缓存将结果传递给 , 它是通过将观察和更新 View 状态的操作包装成 IO .

有了这样的东西,您可以拥有对您的表示和线程协调逻辑进行编码的纯函数,并将结果传递到上述缓存,例如:
fun doNetworkRequest(): IO<Unit> = IO.fx {
!viewStateCache.updateViewState { Loading }
!repository.requestSomeResult().redeemWith(
ft = {
viewStateCache.updateViewState { ErrorViewState(ServerError) }
},
fe = { error ->
viewStateCache.updateViewState { ErrorViewState(error) }
},
fb = { data ->
viewStateCache.updateViewState { SuccessfulViewState(data) }
}
)
}

这些函数不需要存在于 View 模型中,而是使用缓存作为委托(delegate)来传递结果,所以 它可以作为实现细节注入(inject) .

您还需要在 View 创建后立即开始观察 View 状态缓存,这与您已经对 View 模型所做的类似。请注意,我们有意将范围公开为缓存协定的一部分,以便您可以从外部访问它。

这是一个如何包装当前 ViewModel api 以继续使用它们并确保它们的配置更改支持的示例,主要用于逐步迁移到 Arrow。

这种方法更像是一种方便的方法,可能需要一些改进,但应该可以。我们目前正在探索 Android 的常见问题,例如配置更改,以便通过扩展或类似的集成库为那些提供无缝体验。

希望这足够有用,如果没有,请告诉我🙏

关于android - 如何使用 Android ViewModel 实现 Arrow Kt?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60866437/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com