You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改分页扩展方法适配多Fragment及不同ViewModel并修复运行异常

优化后的通用分页滚动监听方案

原代码核心问题

  • 强转LinearLayoutManager,如果RecyclerView使用其他布局管理器会直接崩溃
  • 没有加载状态锁,滑动到底部会连续触发多次接口请求,导致请求错乱、列表跳动
  • 硬编码绑定EverythingViewModel,无法复用到其他业务场景
  • 没有无更多数据的判断,即使后端已经返回完所有数据仍会重复发起无用请求

通用封装实现(Kotlin)

/**
 * 通用RecyclerView分页滚动监听
 * @param visibleThreshold 触发预加载的剩余可见item数量,默认提前1个item开始加载
 * @param isLoading 当前是否正在加载数据,由外部ViewModel维护状态
 * @param hasMoreData 是否还有更多数据可加载,由外部ViewModel维护状态
 * @param onLoadMore 触发分页时的回调,执行具体的分页请求逻辑
 */
fun RecyclerView.addPaginationScrollListener(
    visibleThreshold: Int = 1,
    isLoading: () -> Boolean,
    hasMoreData: () -> Boolean,
    onLoadMore: () -> Unit
): RecyclerView.OnScrollListener {
    val scrollListener = object : RecyclerView.OnScrollListener() {
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)
            // 只有向上滑动、不在加载中、还有更多数据时才判断分页条件
            if (dy <= 0 || isLoading() || !hasMoreData()) return

            val layoutManager = recyclerView.layoutManager as? LinearLayoutManager ?: return
            val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
            val visibleItemCount = layoutManager.childCount
            val totalItemCount = layoutManager.itemCount

            // 满足分页触发条件
            if (visibleItemCount + firstVisibleItemPosition + visibleThreshold >= totalItemCount) {
                onLoadMore()
            }
        }
    }
    this.addOnScrollListener(scrollListener)
    return scrollListener
}

ViewModel适配要求

所有需要使用分页的ViewModel无需继承统一父类,只需要维护三个核心属性、一个请求方法即可:

  • page: Int 当前页码,分页请求时传入接口
  • isLoading: Boolean 加载状态锁,请求开始时设为true,请求结束(成功/失败)都设为false
  • hasMoreData: Boolean 是否还有更多数据,接口返回列表为空/达到总页数时设为false
  • 对应业务的分页请求方法(比如getEverything()、getTopNews()等)

多场景使用示例

原有Everything业务调用

everythingRecycler.addPaginationScrollListener(
    isLoading = { viewModel.isLoading },
    hasMoreData = { viewModel.hasMoreData },
    onLoadMore = {
        viewModel.page++
        viewModel.getEverything()
    }
)

其他业务ViewModel调用(第二个Fragment示例)

topNewsRecycler.addPaginationScrollListener(
    visibleThreshold = 2, // 可自定义提前2个item预加载,提升体验
    isLoading = { topNewsViewModel.isLoading },
    hasMoreData = { topNewsViewModel.hasMoreData },
    onLoadMore = {
        topNewsViewModel.page++
        topNewsViewModel.getTopNews()
    }
)

稳定性优化说明

  • 新增isLoading状态锁,避免同一时间发起多个分页请求
  • 新增hasMoreData判断,无更多数据时不再触发无用请求
  • 布局管理器用安全强转as?,非LinearLayoutManager场景不会崩溃
  • 支持自定义预加载阈值,提前发起请求用户无感知,滑动更流畅

内容的提问来源于stack exchange,提问作者Radin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 04:39:03