以MVI模式提供或发送频道的正确位置 [英] Right place to offer or send Channel in MVI pattern

查看:89
本文介绍了以MVI模式提供或发送频道的正确位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我预先将数据加载到recycleView中.为了做到这一点,我在Activity的onCreate()中有以下代码:

I load data in recycleView in advance. In order to do that I have following code in onCreate() of Activity :

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setupUI()
        setupViewModel()
        observeViewModel()
        if (savedInstanceState == null) {
            mainViewModel.userIntent.offer(MainIntent.FetchUser)
        }
    }

当saveInstanceState为null时,您看到我 offer(),问题是当我们发生进程死亡时(您可以通过激活不将活动保留在开发人员中"选项来简单地创建它),重新加载数据将不会被触发.

As you see I offer() when savedInstanceState is null, The problem is when we have process death ( you can simply create it by activating Do not keep activities in developer option), reload of data will not be triggered.

另一种选择是在ViewModel的 init 块中使用它,但是问题是我想进行波纹管单元测试,可以验证所有三种状态:

another option is to use it inside init block of ViewModel, but problem is I want to have bellow unit test which I can verify all three states :

    @Test
    fun givenServerResponse200_whenFetch_shouldReturnSuccess() {
        runBlockingTest {
            `when`(apiService.getUsers()).thenReturn(emptyList())
            val apiHelper = ApiHelperImpl(apiService)
            val repository = MainRepository(apiHelper)
            val viewModel = MainViewModel(repository)
            viewModel.state.asLiveData().observeForever(observer)
            viewModel.userIntent.send(MainIntent.FetchUser)
        }
        verify(observer, times(3)).onChanged(captor.capture())
        verify(observer).onChanged(MainState.Idle)
        verify(observer).onChanged(MainState.Loading)
        verify(observer).onChanged(MainState.Users(emptyList()))
    }

如果在ViewModel初始化后立即使用init块选项,则会调用 send offer ,而未使用 observeForever 以上单元测试中的LiveData.

If I use the init block option as soon as ViewModel initialized, send or offer will be called while observeForever did not be used for LiveData in the above unit test.

这是我的ViewModel类:

Here is my ViewModel class :

class MainViewModel(
    private val repository: MainRepository
) : ViewModel() {

    val userIntent = Channel<MainIntent>(Channel.UNLIMITED)
    private val _state = MutableStateFlow<MainState>(MainState.Idle)
    val state: StateFlow<MainState>
        get() = _state

    init {
        handleIntent()
    }

    private fun handleIntent() {
        viewModelScope.launch {
            userIntent.consumeAsFlow().collect {
                when (it) {
                    is MainIntent.FetchUser -> fetchUser()
                }
            }
        }
    }

    private fun fetchUser() {
        viewModelScope.launch {
            _state.value = MainState.Loading
            _state.value = try {
                MainState.Users(repository.getUsers())
            } catch (e: Exception) {
                MainState.Error(e.localizedMessage)
            }
        }
    }
}

以上情况的解决方案是什么?

What could be the solution for the above scenarios?

推荐答案

我发现的唯一解决方案是将 fetchUser 方法和另一个 _state 作为MutableStateFlow移至存储库层,并在存储库中 observeForever 进行本地单元测试,因此我可以在ViewModel的init块中发送或提供 userIntent .

The only solution that I found is moving fetchUser method and another _state as MutableStateFlow to Repository layer and observeForever it in Repository for local unit test, as a result I can send or offer userIntent in init block off ViewModel.

在ViewModel中,我将具有以下 _state :

I will have following _state in ViewModel :

val userIntent = Channel<MainIntent>(Channel.UNLIMITED)
    private val _state = repository.state
    val state: StateFlow<MainState>
        get() = _state

这篇关于以MVI模式提供或发送频道的正确位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆