【问题标题】:Live Data Observer called only once. It is not updating the data from server when api is called again to update UILive Data Observer 仅调用一次。再次调用 api 更新 UI 时,它不会从服务器更新数据
【发布时间】:2021-01-10 14:23:54
【问题描述】:

我查找了很多文章并试图了解 Live Data 在使用 MVVM 架构时是如何观察变化的。

我有一个 Fragment A、ViewModel 和 Repository 类。 ViewModel 在片段的onCreateView() 方法中启动。 之后在片段的onCreateView() 方法中启动 API 调用。 来自服务器的数据在片段的onViewCreated 方法中观察

首先,它运行得非常好。但是当我从另一个 Fragment B 更新用户名并返回 Fragment A 时。

在 Fragment A 的 onResume() 方法中再次调用 Api 以更新 UI。 但是这里我的实时数据没有再次被观察到并且 UI 没有更新

我不明白我做错了什么?为什么观察者没有第二次触发?

下面是代码

class FragmentA : Fragment(){

    private lateinit var dealerHomeViewModel: DealerHomeViewModel
  
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_home_dealers, container, false)

        val dealerHomeFactory = DealerHomeFactory(token!!)
        dealerHomeViewModel = ViewModelProvider(this,dealerHomeFactory).get(DealerHomeViewModel::class.java)

      dealerHomeViewModel.getDealerHomeData()
        return view
    }

 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
          dealerHomeViewModel.dealerInfoLiveData.observe(viewLifecycleOwner, androidx.lifecycle.Observer {dealerInfo ->
            // Update UI
            tvDealerName.text = dealerInfo.name
        
        })
    }

 override fun onResume() {
        super.onResume()
        dealerHomeViewModel.getDealerHomeData()
    }
}

//=========================== VIEW MODEL ===================================//
class DealerHomeViewModel(val token:String) : ViewModel() {

    var dealerInfoLiveData:LiveData<DealerInfo>

    init {
        dealerInfoLiveData = MutableLiveData()
    }

    fun getDealerHomeData(){
        dealerInfoLiveData = DealerHomeRepo().getDealerHomePageInfo(token)
    }
}

//======================== REPOSITORY ================================//
class DealerHomeRepo {

    fun getDealerHomePageInfo(token:String):LiveData<DealerInfo>{
        val responseLiveData:MutableLiveData<DealerInfo> = MutableLiveData()
        val apiCall: ApiCall? = RetrofitInstance.getRetrofit()?.create(ApiCall::class.java)
        val dealerInfo: Call<DealerInfo>? = apiCall?.getDealerInfo(Constants.BEARER+" "+token,Constants.XML_HTTP)

        dealerInfo?.enqueue(object : Callback<DealerInfo>{
            override fun onFailure(call: Call<DealerInfo>, t: Throwable) {
                Log.d(Constants.TAG,t.toString())
            }

            override fun onResponse(call: Call<DealerInfo>, response: Response<DealerInfo>) {
                if(response.isSuccessful){
                    when(response.body()?.status){
                        Constants.SUCCESS -> {
                            responseLiveData.value = response.body()
                        }

                        Constants.FAIL -> {

                        }
                    }
                }
            }
        })

        return responseLiveData
    }
}

【问题讨论】:

  • 如果我没记错的话,你应该在 LiveData 上使用 .postValue(result) 而不是 .value = result
  • @GregoryNowik .postValue(result) 与 .value = result 有何不同
  • 我只知道你必须使用 postValue() 而不是暗杀值,因为这是我犯的错误。请参阅:stackoverflow.com/a/53407529/8609783
  • 我怀疑这是否相关。

标签: android mvvm viewmodel android-livedata observer-pattern


【解决方案1】:

我认为您的问题是每次使用 getDealerHomePageInfo(token:String 方法时都会生成一个新的 mutableLiveData。

您第一次调用getDealerHomePageInfo(token:String) 时会生成一个MutableLiveData,然后在onViewCreated 上观察它,它就有一个值。

onResume 中,您再次调用getDealerHomePageInfo(token:String) 会生成一个新的 MutableLiveData,以便您的观察者指向旧的。

解决您的问题的方法是将您的 viewModel 的引用传递给您的存储库,以便它使用每个新值更新 MutableLiveData,而不是每次都生成一个新值。

编辑答案:

我会为ViewModel做这样的事情:

class DealerHomeViewModel(val token:String) : ViewModel() {
    private val _dealerInfoLiveData:MutableLiveData<DealerInfo> = MutableLiveData()
    val dealerInfoLiveData:LiveData = _dealerInfoLiveData


    fun getDealerHomeData(){
        DealerHomeRepo().getDealerHomePageInfo(token, _dealerInfoLiveData)
    }
}

这是DealerHomeRemo

class DealerHomeRepo{

    fun getDealerHomePageInfo(token:String, liveData: MutableLiveData<DealerInfo>){
        val apiCall: ApiCall? = RetrofitInstance.getRetrofit()?.create(ApiCall::class.java)
        val dealerInfo: Call<DealerInfo>? = apiCall?.getDealerInfo(Constants.BEARER+" "+token,Constants.XML_HTTP)

        dealerInfo?.enqueue(object : Callback<DealerInfo>{
            override fun onFailure(call: Call<DealerInfo>, t: Throwable) {
                Log.d(Constants.TAG,t.toString())
            }

            override fun onResponse(call: Call<DealerInfo>, response: Response<DealerInfo>) {
                if(response.isSuccessful){
                    when(response.body()?.status){
                        Constants.SUCCESS -> {
                            liveData.value = response.body()
                        }

                        Constants.FAIL -> {

                        }
                    }
                }
            }
        })
    }

对于观察者,像以前一样使用 LiveData:

dealerHomeViewModel.dealerInfoLiveData.observe(viewLifecycleOwner, androidx.lifecycle.Observer {dealerInfo ->
            // Update UI
            tvDealerName.text = dealerInfo.name
        
        })

【讨论】:

  • 您能否详细说明如何将视图模型传递给 repo 类。
  • 感谢它对我有用。我知道了,我们正在将 MutableLiveData 的新引用从 View Model 发送到 Repo,并且从 Repo 类将更新值并观察实时数据。
  • @Dnveeraj 很好!如果我的回答解决了你的问题,你可以选择它作为接受的答案!
猜你喜欢
  • 1970-01-01
  • 2020-01-29
  • 2018-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多