Android——RecyclerViwe中使用SnapHelper报错:“An instance of OnFlingListener already set.”

文章目录

1.SnapHelper 的应用情景

通常我们使用RecyclerView来实现简单图片轮播图Banner时,需要实现按图片翻页效果,但RecyclerView会在滚动过程中是“过程停留”无法达到“翻页”效果,这时候我们就不得不借助SnapHelper类来使得RecyclerView具备类似ViewPager“翻页”效果的能力。但随着页面UI布局的复杂性,有时候我们需要嵌套RecyclerView并结合SnapHelper。

2.问题现象

多层RecyclerView嵌套时使用SnapHelper工具类配合,向下滚动Item列表正常,但向上滚动会立即强退并杀死app程序。报错问题:“java.lang.IllegalStateException: An instance of OnFlingListener already set.”

3.分析原因

首先来了解一个概念,手指在屏幕上滑动RecyclerView然后松手,RecyclerView中的内容会顺着惯性继续往手指滑动的方向继续滚动直到停止,这个过程叫做Fling。Fling操作从手指离开屏幕瞬间被触发,在滚动停止时结束。而OnFlingListener显然就是监听Fling滚动事件的监听器。

4.原因重点:(SnapHelper被多次创建并绑定到同一个RecyclerView)

通常我们在做RecyclerView的嵌套时总会遇到这样的问题,是因为每次在onBindViewHolder中都这样写:

SnapHelper snapHelper = new PagerSnapHelper()
snapHelper.attachToRecyclerView(recyclerView)

每次滑动RecyclerView都需要重新创建SnapHelper对象并将其附着到RecyclerView上,导致一个RecyclerIView会绑定多个SnapHelper,在回头绘制RecyclerView时,会发现一个RecyclerView的SnapHelper实例(多个)重复设置,导致滚动事件出问题而退出滚动,致使整个app应用崩溃退出!

5.解决方法

5.1第一种方法:

在重新绘制RecyclerView时首先移除创建的前一个SnapHelper实例的OnFlingListener监听器。

Tips:也就是RecyclerView在第二次滑动到该位置时

Java语言

 SnapHelper snapHelper = new PagerSnapHelper()
 recycleView.setOnFlingListener(null)
 snapHelper.attachToRecyclerView(recyclerView)

Kotlin语言

val snapHelper: SnapHelper = PagerSnapHelper()
recycleView.onFlingListener = null
snapHelper.attachToRecyclerView(recyclerView)

Tips:SnapHelper通过attachToRecyclerView()方法附着到RecyclerView上,从而实现辅助RecyclerView滚动对齐操作。

5.2第二种方法:

将SnapHelper snapHelper = new
PagerSnapHelper()放在全局定义(针对类),允许类中只存在一个SnapHelper对象。每次重新绘制RecyclerView时总是调用该SnapHelper实例对象的onFlingListener。

Tips:此方法不用添加任何代码,仅需要将SnapHelper snapHelper = new
PagerSnapHelper()放在与重写方法onBindViewHolder()同级的位置。

6原理剖析

据下面的源码可以看到当与RecyclerView绑定的SnapHelper实例对象的OnFlingListener已经被设置时,再次设置系统会抛出异常:”An instance of OnFlingListener already set.“

7源码解析:

错误类型&具体错误:IllegalArgumentException:An instance of OnFlingListener already set.
 /**
     * Attaches the {@link SnapHelper} to the provided RecyclerView, by calling
     * {@link RecyclerView#setOnFlingListener(RecyclerView.OnFlingListener)}.
     * You can call this method with {@code null} to detach it from the current RecyclerView.
     *
     * @param recyclerView The RecyclerView instance to which you want to add this helper or
     *                     {@code null} if you want to remove SnapHelper from the current
     *                     RecyclerView.
     *
     * @throws IllegalArgumentException if there is already a {@link RecyclerView.OnFlingListener}
     * attached to the provided {@link RecyclerView}.
     *
     */
/**
     * Called when an instance of a {@link RecyclerView} is attached.
     */
    private void setupCallbacks() throws IllegalStateException {
        if (mRecyclerView.getOnFlingListener() != null) {
            throw new IllegalStateException("An instance of OnFlingListener already set.");
        }
        mRecyclerView.addOnScrollListener(mScrollListener);
        mRecyclerView.setOnFlingListener(this);
    }
上一篇:Already included file name。。。。。Root file specified for compilation


下一篇:线性控制原理——PID算法应用