Live Data Observer 只调用了一次。当再次调用 api 更新 UI 时,它不会从服务器更新数据
Live Data Observer called only once. It is not updating the data from server when api is called again to update UI
我找了很多文章,试图了解使用 MVVM 架构时 Live Data 是如何观察变化的。
我有一个 Fragment A、ViewModel 和 Repository class。
ViewModel 在片段的 onCreateView()
方法中启动。
Api 调用是在片段的 onCreateView()
方法之后启动的。
来自服务器的数据在片段的 onViewCreated
方法中 observed。
首先,运行 非常好。但是当我从另一个片段 B 更新用户名并返回到片段 A 时。
Api在Fragment A的onResume()
方法中再次调用,更新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
}
}
我认为您的问题是每次使用 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
})
我找了很多文章,试图了解使用 MVVM 架构时 Live Data 是如何观察变化的。
我有一个 Fragment A、ViewModel 和 Repository class。
ViewModel 在片段的 onCreateView()
方法中启动。
Api 调用是在片段的 onCreateView()
方法之后启动的。
来自服务器的数据在片段的 onViewCreated
方法中 observed。
首先,运行 非常好。但是当我从另一个片段 B 更新用户名并返回到片段 A 时。
Api在Fragment A的onResume()
方法中再次调用,更新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
}
}
我认为您的问题是每次使用 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
})