我有一个片段,我想对其数据进行一次读取,我使用distinctUntilChanged()
来读取一次,因为在此片段期间我的位置没有改变。
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实例,这就是为什么不保留位置的原因,但是如果我将activityViewModels
作为viewmodel的实例,它也发生了同样的事情,数据再次在backpress上加载,这是不可接受的,因为每次返回都会获取数据,这对我来说服务器效率不高,当用户位于此片段中时,如果他们按回以不再获取它,我只需要获取这些数据。
有任何线索吗?
我正在使用导航组件,所以我不能使用.add或执行片段事务,我想在首次创建该片段时只在该片段上获取一次,而不在下一个片段的backpress上重新获取
答案 0 :(得分:0)
当您从片段1->片段2进入时,片段1实际上并没有立即销毁,它只是从ViewModel LiveData取消订阅。
现在,当您从F2返回F1时,该片段将重新订阅到ViewModel LiveData,并且由于LiveData本质上是状态持有者,因此它将立即重新发射其最新值,从而导致ui重新绑定。
您需要的是某种LiveData,它不会发出以前发出的事件。
这是LiveData的常见用例,有一篇不错的文章谈论针对不同类型的用例对类似LiveData的需求,您可以阅读here。
尽管本文提出了几种解决方案,但有时可能有些过分,因此使用以下ActionLiveView
// First extend the MutableLiveData class
class ActionLiveData<T> : MutableLiveData<T>() {
@MainThread
override fun observe(owner: LifecycleOwner, observer: Observer<T?>) {
// Being strict about the observer numbers is up to you
// I thought it made sense to only allow one to handle the event
if (hasObservers()) {
throw Throwable("Only one observer at a time may subscribe to a ActionLiveData")
}
super.observe(owner, Observer { data ->
// We ignore any null values and early return
if (data == null) return
observer.onChanged(data)
// We set the value to null straight after emitting the change to the observer
value = null
// This means that the state of the data will always be null / non existent
// It will only be available to the observer in its callback and since we do not emit null values
// the observer never receives a null value and any observers resuming do not receive the last event.
// Therefore it only emits to the observer the single action so you are free to show messages over and over again
// Or launch an activity/dialog or anything that should only happen once per action / click :).
})
}
// Just a nicely named method that wraps setting the value
@MainThread
fun sendAction(data: T) {
value = data
}
}
如果需要,您可以在this link中找到有关ActionLiveData的更多解释。
我建议使用ActionLiveData类,我已经在小型到中型项目中使用它,到目前为止它可以正常工作,但是同样,您比我更了解用例。 :)