在 Android 的 onClickListener 中多次观察到 LiveData
LiveData is observed multiple times inside onClickListener in Android
我有这样的存储库设置
class ServerTimeRepo @Inject constructor(private val retrofit: Retrofit){
var liveDataTime = MutableLiveData<TimeResponse>()
fun getServerTime(): LiveData<TimeResponse> {
val serverTimeService:ServerTimeService = retrofit.create(ServerTimeService::class.java)
val obs = serverTimeService.getServerTime()
obs.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).unsubscribeOn(Schedulers.io())
.subscribe(object : Observer<Response<TimeResponse>> {
override fun onComplete() {
}
override fun onSubscribe(d: Disposable) {
}
override fun onNext(t: Response<TimeResponse>) {
val gson = Gson()
val json: String?
val code = t.code()
val cs = code.toString()
if (!cs.equals("200")) {
json = t.errorBody()!!.string()
val userError = gson.fromJson(json, Error::class.java)
} else {
liveDataTime.value = t.body()
}
}
override fun onError(e: Throwable) {
}
})
return liveDataTime
}
}
然后我有一个像这样调用这个 repo 的视图模型
class ServerTimeViewModel @Inject constructor(private val serverTimeRepo: ServerTimeRepo):ViewModel() {
fun getServerTime(): LiveData<TimeResponse> {
return serverTimeRepo.getServerTime()
}
}
然后我有一个 activity,我有一个 onClickListener,我在其中观察实时数据,就像这样
tvPWStart.setOnClickListener {
val stlv= serverTimeViewModel.getServerTime()
stlv.observe(this@HomeScreenActivity, Observer {
//this is getting called multiple times??
})
}
我不知道这是怎么回事。谁能指出我正确的方向?谢谢
问题是每次触发 ClickListener 时,您都会一次又一次地观察到 LiveData
。因此,您可以通过以下解决方案解决该问题:
在你的 ViewModel
中私下拿一个 MutableLiveData
对象并观察它 LiveData
.
class ServerTimeViewModel @Inject constructor(private val serverTimeRepo: ServerTimeRepo):ViewModel() {
private val serverTimeData = MutableLiveData<TimeResponse>() // We make private variable so that UI/View can't modify directly
fun getServerTime() {
serverTimeData.value = serverTimeRepo.getServerTime().value // Rather than returning LiveData, we set value to our local MutableLiveData
}
fun observeServerTime(): LiveData<TimeResponse> {
return serverTimeData //Here we expose our MutableLiveData as LiveData to avoid modification from UI/View
}
}
现在,我们直接在 ClickListener
之外观察这个 LiveData
并且我们只是从按钮点击调用 API 方法,如下所示:
//Assuming that this code is inside onCreate() of your Activity/Fragment
//first we observe our LiveData
serverTimeViewModel.observeServerTime().observe(this@HomeScreenActivity, Observer {
//In such case, we won't observe multiple LiveData but one
})
//Then during our ClickListener, we just do API method call without any callback.
tvPWStart.setOnClickListener {
serverTimeViewModel.getServerTime()
}
我有这样的存储库设置
class ServerTimeRepo @Inject constructor(private val retrofit: Retrofit){
var liveDataTime = MutableLiveData<TimeResponse>()
fun getServerTime(): LiveData<TimeResponse> {
val serverTimeService:ServerTimeService = retrofit.create(ServerTimeService::class.java)
val obs = serverTimeService.getServerTime()
obs.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).unsubscribeOn(Schedulers.io())
.subscribe(object : Observer<Response<TimeResponse>> {
override fun onComplete() {
}
override fun onSubscribe(d: Disposable) {
}
override fun onNext(t: Response<TimeResponse>) {
val gson = Gson()
val json: String?
val code = t.code()
val cs = code.toString()
if (!cs.equals("200")) {
json = t.errorBody()!!.string()
val userError = gson.fromJson(json, Error::class.java)
} else {
liveDataTime.value = t.body()
}
}
override fun onError(e: Throwable) {
}
})
return liveDataTime
}
}
然后我有一个像这样调用这个 repo 的视图模型
class ServerTimeViewModel @Inject constructor(private val serverTimeRepo: ServerTimeRepo):ViewModel() {
fun getServerTime(): LiveData<TimeResponse> {
return serverTimeRepo.getServerTime()
}
}
然后我有一个 activity,我有一个 onClickListener,我在其中观察实时数据,就像这样
tvPWStart.setOnClickListener {
val stlv= serverTimeViewModel.getServerTime()
stlv.observe(this@HomeScreenActivity, Observer {
//this is getting called multiple times??
})
}
我不知道这是怎么回事。谁能指出我正确的方向?谢谢
问题是每次触发 ClickListener 时,您都会一次又一次地观察到 LiveData
。因此,您可以通过以下解决方案解决该问题:
在你的
ViewModel
中私下拿一个MutableLiveData
对象并观察它LiveData
.class ServerTimeViewModel @Inject constructor(private val serverTimeRepo: ServerTimeRepo):ViewModel() { private val serverTimeData = MutableLiveData<TimeResponse>() // We make private variable so that UI/View can't modify directly fun getServerTime() { serverTimeData.value = serverTimeRepo.getServerTime().value // Rather than returning LiveData, we set value to our local MutableLiveData } fun observeServerTime(): LiveData<TimeResponse> { return serverTimeData //Here we expose our MutableLiveData as LiveData to avoid modification from UI/View } }
现在,我们直接在
ClickListener
之外观察这个LiveData
并且我们只是从按钮点击调用 API 方法,如下所示://Assuming that this code is inside onCreate() of your Activity/Fragment //first we observe our LiveData serverTimeViewModel.observeServerTime().observe(this@HomeScreenActivity, Observer { //In such case, we won't observe multiple LiveData but one }) //Then during our ClickListener, we just do API method call without any callback. tvPWStart.setOnClickListener { serverTimeViewModel.getServerTime() }