发现问题
当我们在处理ListView滚动到底部加载更多时,通常的做法是利用OnScrollListener的onScroll方法,来判断是否滚动到了底部。
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
boolean toBottom = firstVisibleItem + visibleItemCount >= totalItemCount;
if (toBottom && !isLoading && !isFinish) {
//...
}
}
但是这种做法会引发一系列的问题,比如当初始化ListView,并setOnScrollListener时便会回调onScroll方法,此时得到的结果是已经滚动到了底部,在没有任何数据的情况下给出这样一个结果,会对程序的处理逻辑产生影响。
看看源码:
/**
* Set the listener that will receive notifications every time the list scrolls.
*
* @param l the scroll listener
*/
public void setOnScrollListener(OnScrollListener l) {
mOnScrollListener = l;
invokeOnItemScrollListener();
}
/**
* Notify our scroll listener (if there is one) of a change in scroll state
*/
void invokeOnItemScrollListener() {
if (mFastScroll != null) {
mFastScroll.onScroll(mFirstPosition, getChildCount(), mItemCount);
}
if (mOnScrollListener != null) {
mOnScrollListener.onScroll(this, mFirstPosition, getChildCount(), mItemCount);
}
onScrollChanged(0, 0, 0, 0); // dummy values, View's implementation does not use these.
}
也就是说,在setOnScrollListener时便已经回调了onScroll方法。
解决问题
大多数情况下,大家都忽略了OnScrollListener中的onScrollStateChanged方法。
public void onScrollStateChanged(AbsListView view, int scrollState);
该方法有两个入参,第二个参数scrollState有三种状态:
public static int SCROLL_STATE_IDLE = 0; //结束滚动
public static int SCROLL_STATE_TOUCH_SCROLL = 1; //触摸滚动
public static int SCROLL_STATE_FLING = 2; //手指离开屏幕后的滚动状态
此时我们可将焦点定位到 SCROLL_STATE_IDLE,将滚动到底部的判断和处理放在结束滚动之后。
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case SCROLL_STATE_IDLE:
boolean toBottom = view.getLastVisiblePosition() == view.getCount() - 1;
if (toBottom && !isLoading && !isFinish) {
//...
}
break;
}
这样便可完美解决onScroll的频繁调用,及首次调用的问题;同时,也成功解决了滚动到底部的逻辑判断和处理。
网友评论