上一篇 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);
}
@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);
}
if(mAdapter.getScrolling() && scrlled) {
//对于滚动不加载图片的尝试
mAdapter.setScrolling(false);
mAdapter.notifyDataSetChanged();
}
scrolled是用来判断列表有没有发生滚动位移。
判断的地方RecyclerView的OnScrollListener的onScrolled方法:
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if(dy != 0){
scrlled = true;
}
}
为什么要加这个判断条件?
这是为了解决一个bug,如果列表在顶部或者底部,如果快速的在屏幕上向下或向上滑动,onFling可以监听到v1大于4000,并且onScrollStateChanged的RecyclerView.SCROLL_STATE_IDLE也会有监听,所以加一个额外条件,如果列表没有任何滚动,则不做任何操作。
git源码:RefreshRecyclerView
介绍文章:RefreshRecyclerView下拉刷新上拉加载