Kotlin中RecyclerView加载更多时保留原有数据、避免旧内容被替换的解决方案
RecyclerView滚动加载更多数据被覆盖问题修复方案
问题根因
你的代码存在三处核心错误,导致旧数据被覆盖、列表展示异常:
- ViewModel拉取分页数据后直接替换全量列表,没有将新数据追加到原有列表末尾
- Adapter分页插入数据的通知方法使用错误,且插入起始位置计算错误
- 滚动监听中重复注册数据观察者,且加载状态控制逻辑错误
修复代码
1. ViewModel层修改
// 新增refresh方法实现,下拉刷新时重置分页和列表 fun refresh() { pageNumber = 1 fetchPhotos(isRefresh = true) } fun fetchMorePhotos() { pageNumber += 1 fetchPhotos(isRefresh = false) } private fun fetchPhotos(isRefresh: Boolean) { loading.value = true disposable.add( PhotosService.getPhotos(pageNumber) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribeWith(object : DisposableSingleObserver<List<PhotoData>>() { override fun onSuccess(value: List<PhotoData>?) { value ?: return // 刷新直接替换列表,加载更多追加数据 Photos.value = if (isRefresh) { value } else { (Photos.value ?: emptyList()) + value } PhotoLoadError.value = false loading.value = false } override fun onError(e: Throwable?) { PhotoLoadError.value = true loading.value = false // 加载失败回退页码 if (!isRefresh) pageNumber -= 1 } }) ) }
2. Adapter层修改
class PhotoListAdapter( var photos: ArrayList<PhotoData>, private var click_listener: OnPhotoItemClickListner ) : RecyclerView.Adapter<PhotoListAdapter.PhotoViewHolder>() { // 全量更新,用于下拉刷新 fun updatePhotos(newPhotos: List<PhotoData>) { photos.clear() photos.addAll(newPhotos) notifyDataSetChanged() } // 追加数据,用于分页加载更多 fun getMorePhotos(newPhotos: List<PhotoData>) { val insertStartPosition = photos.size photos.addAll(newPhotos) // 用范围插入通知,而不是修改通知,性能更好且不会触发旧item重绘 notifyItemRangeInserted(insertStartPosition, newPhotos.size) } }
3. Fragment层修改
// 初始化只执行一次 photosList.layoutManager = LinearLayoutManager(context) photosList.adapter = photosAdapter // 只注册一次观察者,不要每次加载都重复注册 observeViewModel() viewModel.refresh() // 滚动监听修改 photosList.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) if (dy <= 0) return // 只处理向下滚动 val layoutManager = photosList.layoutManager as LinearLayoutManager val totalItemCount = layoutManager.itemCount val lastVisibleItem = layoutManager.findLastVisibleItemPosition() // 监听ViewModel的loading状态,避免重复触发加载 if (!viewModel.loading.value!! && lastVisibleItem >= totalItemCount - 2) { // 提前2个item触发加载,体验更流畅 viewModel.fetchMorePhotos() } } }) // 观察者统一处理逻辑 private fun observeViewModel() { viewModel.Photos.observe(viewLifecycleOwner) { list -> // 首次加载/刷新调用update,加载更多调用getMore if (viewModel.pageNumber == 1) { photosAdapter.updatePhotos(list) } else { photosAdapter.getMorePhotos(list.subList(photosAdapter.photos.size, list.size)) } } // 其他loading、错误状态监听统一放在这里处理 }
内容的提问来源于stack exchange,提问作者abed sh
相关产品推荐
相关产品推荐

