【问题标题】:ViewModel emiting multiple times instead of just onceViewModel 发出多次而不是一次
【发布时间】:2020-08-28 08:29:42
【问题描述】:

我试图在这个片段中只发出一次,它在我第一次进入这个片段时发出,但是如果我导航到下一个片段并返回,它会再次发出,我不希望那样,因为它会重新获取我的数据,相反,如果我回到这个片段,我想避免重新获取。

片段

 private val viewModel by viewModels<LandingViewModel> {
        VMLandingFactory(
            LandingRepoImpl(
                LandingDataSource()
            )
        )
    }

 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val sharedPref = requireContext().getSharedPreferences("LOCATION", Context.MODE_PRIVATE)
        val nombre = sharedPref.getString("name", null)
        location = name!!
    }

 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        setupRecyclerView()
        fetchShops(location)
    }

 private fun fetchShops(localidad: String) {

        viewModel.setLocation(location.toLowerCase(Locale.ROOT).trim())
        viewModel.fetchShopList
            .observe(viewLifecycleOwner, Observer {

                when (it) {

                    is Resource.Loading -> {
                        showProgress()
                    }
                    is Resource.Success -> {
                        hideProgress()
                        myAdapter.setItems(it.data)
                    }
                    is Resource.Failure -> {
                        hideProgress()
                        Toast.makeText(
                            requireContext(),
                            "There was an error loading the shops.",
                            Toast.LENGTH_SHORT
                        ).show()
                    }
                }
            })

    }

视图模型

 private val locationQuery = MutableLiveData<String>()

    fun setLocation(location: String) {
        locationQuery.value = location
    }

    val fetchShopList = locationQuery.distinctUntilChanged().switchMap { location ->
        liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
            emit(Resource.Loading())
            try{
                emit(repo.getShopList(location))
            }catch (e:Exception){
                emit(Resource.Failure(e))
            }
        }
        }

在这里,当我转到下一个片段并返回时,位置并没有改变。任何想法如何解决这一问题 ?我正在使用导航组件。

【问题讨论】:

  • 如果您进行底部导航,请停留在片段上并在底部导航的同一片段上点击两次,它会一次又一次地发出值,然后它不是 viewModel 观察者问题,但您的片段会重新创建,我有点同意下面是@Joozd 的回答......以及为什么你在 switchMap 块中阅读不同的情况?在存储库中执行此操作并保持 switchMap 有点干净。

标签: android android-fragments kotlin mvvm android-architecture-navigation


【解决方案1】:

LiveData 就是这样工作的,它会在恢复时始终为您提供最新信息。我建议使用 kotlin 的 Flow,因为这可以满足您的要求,在您完成发射后,您将不再获得更新

【讨论】:

  • 但是我不需要响应式获取数据,我只需要获取一次,这必须是片段状态
  • 不,不是,实时数据将始终为您提供现有数据,因此您可以在加载新数据时显示内容。直接来自文档If a lifecycle becomes inactive, it receives the latest data upon becoming active again. For example, an activity that was in the background receives the latest data right after it returns to the foreground.
  • 使用Flow,您发出一次,然后就完成了。 Flow 类似于您订阅它的实时数据,但在活动/片段再次激活时完成了回调
  • 但这与后台的活动片段无关,而是关于导航到另一个片段(销毁当前片段)并返回,视图模型也将由于生命周期所有者而被分离和销毁,然后再次创建并重新获取(再次发出)与流将是相同的
  • 如果一切都像你说的那样被破坏了,那么当然你仍然会得到数据,因为 onViewCreated 将被再次调用,它调用fetchShops(location) 不确定你在这里期望什么,如果你不想要什么会显示重新获取?
【解决方案2】:

尝试使用SingleLiveEvent 它应该只发射一次

【讨论】:

    【解决方案3】:

    我昨天看到了你的问题,试图研究我没有成功回答为什么 distinctUntilChanged() 对你不起作用 - 老实说,我从未使用过添加的“扩展”不久前。

    无论如何,快速修复是添加一个 alreadyLoaded 变量,如下所示:

     private val locationQuery = MutableLiveData<String>()
    
     private var alreadyLoaded = false
    
        fun setLocation(location: String) {
        if (!alreadyLoaded) {
            alreadyLoaded = true
            locationQuery.value = location
         }
    
        }
    
        val fetchShopList = locationQuery.distinctUntilChanged().switchMap { location ->
            liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
                emit(Resource.Loading())
                try{
                    emit(repo.getShopList(location))
                }catch (e:Exception){
                    emit(Resource.Failure(e))
                }
            }
            }
    

    【讨论】:

      【解决方案4】:

      视图模型不会多次发射。您的活动得到重新创建,因此您观察不止一次。 (旋转屏幕等时也会发生)

      Thisgentleman 有一个关于这种情况的非常好的和清晰的博客

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-04
        • 2016-04-21
        • 2022-01-25
        • 2020-01-17
        • 2016-09-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多