RecyclerView 卡顿优化(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/likuan0214/article/details/51911873

上一篇 RecyclerView 卡顿优化(一)主要介绍了基本的优化思路及简单代码,对于布局不太复杂,基本够用了。

此篇主要介绍在上一篇的基础上,进行的进一步优化,及最后提供一个Demo(RecyclerView  + 下拉刷新 + 上拉加载 + 滚动不加载优化)。


上一篇介绍到监听RecyclerView的OnScrollListener的onScrollStateChanged方法进行监听,当滚动停止时,刷新界面,实现加载。

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                Log.i(TAG, "stated:" + newState + "  time:" + System.currentTimeMillis());
                switch (newState){
                    case RecyclerView.SCROLL_STATE_IDLE: // The RecyclerView is not currently scrolling.
                        scroll_count ++;
//                        Log.i("scroll_state", "state:" + "停止");
                        if(mAdapter.getScrolling() && scrlled) {
                            //对于滚动不加载图片的尝试
                            mAdapter.setScrolling(false);
                            mAdapter.notifyDataSetChanged();
                        }

                        scrlled = false;
                        break;
                    case RecyclerView.SCROLL_STATE_DRAGGING: // The RecyclerView is currently being dragged by outside input such as user touch input.
//                        mAdapter.setScrolling(false);
//                        Log.i("scroll_state", "state:" + "拖拽");
                        break;
                    case RecyclerView.SCROLL_STATE_SETTLING: // The RecyclerView is currently animating to a final position while not under
//                        mAdapter.setScrolling(true);
//                        Log.i("scroll_state", "state:" + "滚动到某地");
                        break;
                }
                super.onScrollStateChanged(recyclerView, newState);
            }
这一点的优点很明显,不需要对当前屏幕显示的ViewHoler进行手动加载,直接交给mAdapter.notifyDataSetChanged()方法来刷新即可。

但是,缺点也很明显,就是用户稍微滚动一下界面,就要刷新一次,这样做在用户体验及交互上会有一定问题。

因此,就要考虑加载及不加载的时机。




优化前:列表只要滚动停止就加载,不管用户滚动了多少,不管是否快速滚动。


思路:

1.能否检测是不是快速滚动,只有快速滚动中不加载图片及复杂布局。

2.滚动停止时,判断是否存在图片或布局未加载,如果有,才加载。否则,不做任何操作。

3.如何判断快速滚动?

对于快速滚动的监听,方法有很多,比如列表滚动中计算一下滚动速度,如果速度大于某个值,我们就认为是快速滚动。


优化过程:

1.之前一直没有用过的GestureDetector.OnGestureListener监听,所以就尝试用了此方法。

    public interface OnGestureListener {
        boolean onDown(MotionEvent var1);

        void onShowPress(MotionEvent var1);

        boolean onSingleTapUp(MotionEvent var1);

        boolean onScroll(MotionEvent var1, MotionEvent var2, float var3, float var4);

        void onLongPress(MotionEvent var1);

        boolean onFling(MotionEvent var1, MotionEvent var2, float var3, float var4);
    }


这里主要用到了onFling方法

    @Override
    public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
        Log.i(TAG, "onFling: " + Math.abs(v1));
        if(Math.abs(v1) > 4000){
            mAdapter.setScrolling(true);
        }
        return false;
    }

v是x方向滑动速度,v1是y方向滑动速度。

选择Math.abs(v1) > 4000来作为快速滑动的判断原因,自己测出来的。。。这个可以自己测试来定,一般快速滑动时,v1的值在4000+。


所以就解决了我们的第一个问题,快速滑动的监听,如果是快速滑动,就不加载图片。


2.通过判断mAdapter.getScrolling()是否为true,来判断是不是有未加载图片。

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                Log.i(TAG, "stated:" + newState + "  time:" + System.currentTimeMillis());
                switch (newState){
                    case RecyclerView.SCROLL_STATE_IDLE: // The RecyclerView is not currently scrolling.
                        scroll_count ++;
//                        Log.i("scroll_state", "state:" + "停止");
                        if(mAdapter.getScrolling() && scrlled) {
                            //对于滚动不加载图片的尝试
                            mAdapter.setScrolling(false);
                            mAdapter.notifyDataSetChanged();
                        }

                        scrlled = false;
                        break;
                    case RecyclerView.SCROLL_STATE_DRAGGING: // The RecyclerView is currently being dragged by outside input such as user touch input.
//                        mAdapter.setScrolling(false);
//                        Log.i("scroll_state", "state:" + "拖拽");
                        break;
                    case RecyclerView.SCROLL_STATE_SETTLING: // The RecyclerView is currently animating to a final position while not under
//                        mAdapter.setScrolling(true);
//                        Log.i("scroll_state", "state:" + "滚动到某地");
                        break;
                }
                super.onScrollStateChanged(recyclerView, newState);
            }

3.细心的读者,可以发现多一个scrolled条件判断。

                        if(mAdapter.getScrolling() && <span style="color:#ff0000;">scrlled</span>) {
                            //对于滚动不加载图片的尝试
                            mAdapter.setScrolling(false);
                            mAdapter.notifyDataSetChanged();
                        }


scrolled是用来判断列表有没有发生滚动位移。

判断的地方RecyclerView的OnScrollListener的onScrolled方法:

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

<span style="color:#ff0000;">                if(dy != 0){
                    scrlled = true;
                }</span>
}
为什么要加这个判断条件?

这是为了解决一个bug,如果列表在顶部或者底部,如果快速的在屏幕上向下或向上滑动,onFling可以监听到v1大于4000,并且onScrollStateChanged的RecyclerView.SCROLL_STATE_IDLE也会有监听,所以加一个额外条件,如果列表没有任何滚动,则不做任何操作。

git源码:RefreshRecyclerView

介绍文章:RefreshRecyclerView下拉刷新上拉加载


猜你喜欢

转载自blog.csdn.net/likuan0214/article/details/51911873