Android RecyclerView + Paging Library 添加头部刷新会自动滚动的问题分析及解决

本文分析了在使用RecyclerView + Paging Library时,添加头部刷新导致数据加载完成后自动滚动的问题。问题根源在于Header的存在使position不准确。通过研究源码,作者发现可以通过覆盖Adapter的registerAdapterDataObserver方法,创建一个代理类来处理Header数量,从而在插入、删除操作前调整正确的position。文章提供了问题解决方案并讨论了Paging Library在添加和删除item时的挑战。
摘要由CSDN通过智能技术生成

一、前言

最近在做一款应用,因为 api 涉及到分页的,所以选择用 RecyclerView + Paging 去做,能省去向下滚动时去处理加载下一页的数据的逻辑,Paging 会自动去加载下一页的内容,首页要做个 Banner, 所以把 Banner 作为 RecyclerView 的 头添加进去,可是添加后下面的数据加载完就会自动滚到下面去,如下图,一下拉刷新,加载完数据后就滚到下面去了

运行结果截图

二、问题分析

当我去掉头部刷新,一切是正常的,

运行结果截图

所以原因应该就是添加了 Header,导致 position 不准确, RecyclerView 不知道有 Header 的存在,一刷新插入、删除等操作是从 0 开始的,但 Header 在前面霸占着位置了(陈独秀同学在前面站着不坐下),所以插入、删除等操作不要动到 Header 的位置,使其操作正确的 position, 那怎么让其不去动到 Heasder 的位置呢?只有看看源码能不能找到解决的办法了, RecyclerView + Paging Library 用的 Adapter 用的是继承 PagedListAdapter 的,

运行结果截图

PagedListAdapter 是使用了 DiffUtil 的,DiffUtil 里的插入、删除等操作是用到 AdapterListUpdateCallback 这个类

运行结果截图

运行结果截图

AdapterListUpdateCallback 这个类里插入、删除等操作调用的是 RecyclerView.Adapter mAdapter 的,

/**
 * ListUpdateCallback that dispatches update events to the given adapter.
 *
 * @see DiffUtil.DiffResult#dispatchUpdatesTo(RecyclerView.Adapter)
 */
public final class AdapterListUpdateCallback implements ListUpdateCallback {
   
    @NonNull
    private final RecyclerView.Adapter mAdapter;

    /**
     * Creates an AdapterListUpdateCallback that will dispatch update events to the given adapter.
     *
     * @param adapter The Adapter to send updates to.
     */
    public AdapterListUpdateCallback(@NonNull RecyclerView.Adapter adapter) {
        mAdapter = adapter;
    }

    /** {@inheritDoc} */
    @Override
    public void onInserted(int position, int count) {
        mAdapter.notifyItemRangeInserted(position, count);
    }

    /** {@inheritDoc} */
    @Override
    public void onRemoved(int position, int count) {
        mAdapter.notifyItemRangeRemoved(position, count);
    }

    /** {@inheritDoc} */
    @Override
    public void onMoved(int fromPosition, int toPosition) {
        mAdapter.notifyItemMoved(fromPosition, toPosition);
    }

    /** {@inheritDoc} */
    @Override
    public void onChanged(int position, int count, Object payload) {
        mAdapter.notifyItemRangeChanged(position, count, payload);
    }
}

RecyclerView.Adapter 里用的是 mObservable 的插入、删除等操作,

运行结果截图

这个 mObservable 是 AdapterDataObservable 类型的,

运行结果截图

AdapterDataObservable 是继承 Observable 的

static class AdapterDataObservable extends Observable<AdapterDataObserver> {
    public boolean hasObservers() {
        return !mObservers.isEmpty();
    }
    public void notifyChanged() {
        // since onChanged() is implemented by the app, it could do anything, including
        // removing itself from {@link mObservers} - and that could cause problems if
        // an iterator is used on the ArrayList {@link mObservers}.
        // to avoid such problems, just march thru the list in the reverse order.
        for (int i = mObservers.size() - 1; i >= 0; i--) {
            mObservers.get(i).onChanged();
        }
    }
    public void notifyItemRangeChanged(int positionStart, int itemCount) {
        notifyItemRangeChanged(positionStart, itemCount, null);
    }
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值