Android Kotlin 从其他Fragment返回时如何避免列表Fragment重复调用接口
问题根本原因
使用Navigation组件导航时,ListFragment跳转到MapFragment后视图会被销毁,返回时触发视图重建,onViewCreated生命周期重新执行,因此方法内的接口请求会被重复调用。
解决方案
方案1:ViewModel层加请求状态判断(最推荐)
ViewModel生命周期长于Fragment视图,不会随页面切换销毁,可在请求方法中添加状态校验,避免重复触发请求:
fun getMeteorsData(){ // 正在请求中 或 已有成功返回的缓存数据,直接跳过请求 if (_isLoading.value == true || _getMeteorsResponse.value?.status == Resource.Status.SUCCESS) { return } _isLoading.value = true // 原有请求逻辑保持不变 disposable.add( meteorsRepository.getMeteors() .subscribeOn(Schedulers.newThread()) .observeOn(io.reactivex.android.schedulers.AndroidSchedulers.mainThread()) .subscribeWith(object : DisposableSingleObserver<ArrayList<MeteorModel>>(){ override fun onSuccess(response : ArrayList<MeteorModel>) { _isLoading.value = false _getMeteorsResponse.value = Resource.success(response) } override fun onError(e: Throwable) { _isLoading.value = false _getMeteorsResponse.value = Resource.error(e.message ?: "Error", null) Log.e(TAG, e.message.toString()) } }) ) }
如果需要手动刷新(如下拉刷新),触发时先调用resetMeteors()清空缓存数据,再发起请求即可正常拉取最新数据。
方案2:Fragment层按需调用接口
在onViewCreated中先判断ViewModel是否有缓存数据,无数据时再发起请求:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val backBtn: AppCompatImageView = requireActivity().findViewById(R.id.back_btn) backBtn.visibility = View.GONE binding.swipeRefreshMeteors.setOnRefreshListener { binding.swipeRefreshMeteors.isRefreshing = false getMeteorsDetails() } // 仅无缓存数据时调用接口 if (meteorsViewmodel.getMeteorsResponse.value == null) { getMeteorsDetails() } observeIsLoading() observeMeteorsData() }
方案3:缓存Fragment视图避免重建
缓存Fragment根视图,返回时直接复用原有视图,不需要重新走生命周期逻辑,还能保留列表滚动位置:
private var _binding: FragmentMeteorListBinding? = null private val binding get() = _binding!! // 全局缓存根视图 private var rootView: View? = null override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { if (rootView == null) { _binding = FragmentMeteorListBinding.inflate(inflater, container, false) rootView = binding.root } else { // 移除原有父布局,避免重复添加报错 (rootView?.parent as? ViewGroup)?.removeView(rootView) } return rootView!! } override fun onDestroyView() { super.onDestroyView() // 清空绑定避免内存泄漏 _binding = null }
内容的提问来源于stack exchange,提问作者Razvan22
相关产品推荐
相关产品推荐

