onScroll вызывается, когда я устанавливаю listView.onScrollListener (this), но без какого-либо прикосновения

Когда я устанавливаю onScrollListener для своего ListView, он вызывает onScroll. Это вызывает сбой, потому что некоторые вещи не были инициализированы.

Это нормально? Примечание: это происходит без того, чтобы я даже касался телефона.

public class MainActivity1 extends Activity implements OnClickListener, OnScrollListener {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.layout1);

    ListView lv = (ListView)findViewById(R.id.listview1);
    lv.setOnScrollListener(this);
    ...
}
...
public void onScroll(AbsListView view, int firstVisibleItem,
        int visibleItemCount, int totalItemCount){
    if( firstVisibleItem+visibleItemCount == totalItemCount ){
        pullContactList();
    }
}

person Siavash    schedule 18.04.2013    source источник
comment
здесь что-то не так . oncreate - это первый метод, который вызывается из активности   -  person stinepike    schedule 18.04.2013
comment
мой плохой, он фактически вызывается, когда onCreate вызывает setOnScrollListner. это нормально?   -  person Siavash    schedule 18.04.2013
comment
что не было инициализировано? Что в pullContactList ()?   -  person LuxuryMode    schedule 18.04.2013
comment
да. А также мой адаптер. Я знаю, что могу вызвать setonscrolllistner в конце моего oncreate. Или используйте переменную в onscroll, чтобы пропустить ее содержимое при первом вызове. Но это все патчи. Есть ли способ заставить setonscrolllistner не вызывать onscroll? Надо ли перебивать конструктор?   -  person Siavash    schedule 18.04.2013
comment
Лучший stackoverflow.com/a/6357973/1318946   -  person Pratik Butani    schedule 05.05.2014


Ответы (5)


Это нормально, потому что исходный код setOnScrollListener в AbsListView (суперкласс ListView) делает следующее:

 public void setOnScrollListener(OnScrollListener l) {
        mOnScrollListener = l;
        invokeOnItemScrollListener();
    }

и invokeOnItemScrollListener делает это:

/**
     * Notify our scroll listener (if there is one) of a change in scroll state
*/
    void invokeOnItemScrollListener() {
        if (mFastScroller != null) {
            mFastScroller.onScroll(this, 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.
    }

в зависимости от того, что вы пытаетесь сделать, есть несколько способов избежать этой проблемы.

РЕДАКТИРОВАТЬ:

Поскольку вы хотите сделать это только в том случае, если пользователь действительно прокручивает, я полагаю, вы могли бы сделать что-то вроде:

    lv.setOnTouchListener(new OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    if(view == lv && motionEvent.getAction() == MotionEvent.ACTION_SCROLL) {
                      userScrolled = true;
    }
return false;
                }
            });

Потом..

lv.setOnScrollListener(new AbsListView.OnScrollListener() {
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount){
        if(userScrolled && firstVisibleItem+visibleItemCount == totalItemCount ){
            pullContactList();
        }
    }

});
person LuxuryMode    schedule 18.04.2013
comment
Я просто хочу, чтобы onScroll не вызывался в первый раз, я хочу, чтобы он вызывался только тогда, когда пользователь прокручивает. Спасибо. (я понимаю, что могу переместить setonscrolllistner на более поздний этап кода, но я хочу узнать, как сделать это по-другому) - person Siavash; 18.04.2013
comment
для полноты: вы забыли оператор возврата в слушателе onTouch - person Geert Bellemans; 12.06.2013
comment
Я не могу поверить, что поведение не упоминается в документации. - person blahdiblah; 13.09.2014
comment
Это вызывает утечку батареи? Я имею в виду, это нормально? - person VSB; 10.10.2014
comment
ответ ниже простой и правильный. Понятия не имею, почему ОП выбрал именно этот. - person Sufian; 16.01.2015
comment
thumbsup за упоминание того, что Android делает сзади при настройке onScrollListener - person vida; 06.07.2017

Просто напоминание, согласно javadoc

MotionEvent.ACTION_SCROLL :

Это действие всегда доставляется окну или представлению под указателем, которое может не быть окном или представлением, к которому в данный момент прикоснулись.

Это действие не является событием касания, поэтому оно доставляется в onGenericMotionEvent (MotionEvent), а не в onTouchEvent (MotionEvent).

Следовательно, motionEvent.getAction() никогда не получит событие SCROLL. Убедитесь, что MOVE выполнит свою работу

Вы также можете сделать то же самое в onScrollStateChanged методе OnScrollListener

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
        if(scrollState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL){
            userScrolled = true;
        }   
}
person Community    schedule 22.08.2013
comment
привет, когда-нибудь метод onScrollStateChanged() не вызывается, например, когда вызывается метод adapter.notificationDataSetChange(), он будет пропущен из этого метода и в метод onScrollStateChanged(). поэтому этот метод не подходит - person Carl; 27.11.2014
comment
Я знаю, что это старый ответ, но я сам наткнулся на эту проблему. Я понимаю, почему это происходит, когда читаю исходный код для AbsListView, но не понимаю, почему это должно происходить. Может ли кто-нибудь просветить меня? - person Darwind; 09.03.2015
comment
Если вы отредактируете свой ответ так, что это будет отдельный ответ, я приму его как лучший ответ. В настоящее время это похоже на приложение к другому главному ответу. - person Siavash; 17.05.2016

Я использую это решение, и оно мне подходит:

public void onScrollStateChanged(AbsListView view, int scrollState) {
            if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
                canScroll = false;
            } else if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING ||
                    scrollState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
                canScroll = true;

            }
        }
person Farzad Farazmand    schedule 14.05.2016

Вы можете выполнить необходимую задачу, только если visibleItemCount> 0;

public void onScroll(AbsListView view, int firstVisibleItem,
        int visibleItemCount, int totalItemCount){
    if (visibleItemCount > 0 ){
        //perform the task to be done
    }
}
person Varun Bhatia    schedule 14.01.2015

Сработало решение для меня !!! комбинация вышеуказанного ответа я принял решение !! благодаря @LuxuryMode и @CrazyGreenHand

Мой TouchListener: поскольку MotionEvent.ACTION_SCROLL не запускается, я использовал действие MOVE

 expandableListView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            if(view == expandableListView && motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
                userScrolled = true;
            }
            return false;
        }
    });

Мой слушатель прокрутки:

  expandableListView.setOnScrollListener(new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView absListView, int i) {

        }

        @Override
        public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            if (firstVisibleItem == 0){
                swipeRefreshLayout.setEnabled(true);
            }else {
                swipeRefreshLayout.setEnabled(false);
            }
            int lastVisibleItem = absListView.getLastVisiblePosition();
            if (userScrolled&&!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                onLoadMore();
                isLoading = true;
            }
            Log.d(TAG, "onScroll: firstVisibleItem=>"+firstVisibleItem+"==>visibleItemCount=>"+visibleItemCount+"==>totalItemCount==>"+totalItemCount+"==>lastVisibleItem==>"+lastVisibleItem);
        }
    });
person prasanthMurugan    schedule 01.12.2016