Android ViewPager выдает исключение IndexOutOfBounds при настройке текущего элемента/страницы

У меня есть ViewPager с тремя элементами. Я пытаюсь настроить ViewPager для просмотра самой дальней страницы справа (которая будет вторым элементом). Это возвращает исключение IndexOutOfBounds, хотя я знаю, что индекс должен быть в границах. Вот точный стек:

02-22 12:22:50.256: E/AndroidRuntime(384): FATAL EXCEPTION: main
02-22 12:22:50.256: E/AndroidRuntime(384): java.lang.IndexOutOfBoundsException: index=1 count=0
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.view.ViewGroup.addInArray(ViewGroup.java:2050)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.view.ViewGroup.addViewInner(ViewGroup.java:1994)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.view.ViewGroup.addViewInLayout(ViewGroup.java:1958)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.view.ViewGroup.addViewInLayout(ViewGroup.java:1939)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.support.v4.view.ViewPager.addView(ViewPager.java:917)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.view.ViewGroup.addView(ViewGroup.java:1828)
02-22 12:22:50.256: E/AndroidRuntime(384):  at us.tagverse.pagertest.MasterActivity$PAdapter.instantiateItem(MasterActivity.java:518)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.support.v4.view.PagerAdapter.instantiateItem(PagerAdapter.java:110)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:649)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.support.v4.view.ViewPager.populate(ViewPager.java:783)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1016)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.view.View.measure(View.java:8313)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:3138)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1017)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.widget.LinearLayout.measureVertical(LinearLayout.java:386)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.widget.LinearLayout.onMeasure(LinearLayout.java:309)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.view.View.measure(View.java:8313)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:3138)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.widget.FrameLayout.onMeasure(FrameLayout.java:250)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.view.View.measure(View.java:8313)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:3138)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.widget.FrameLayout.onMeasure(FrameLayout.java:250)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.view.View.measure(View.java:8313)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.view.ViewRoot.performTraversals(ViewRoot.java:839)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.view.ViewRoot.handleMessage(ViewRoot.java:1859)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.os.Handler.dispatchMessage(Handler.java:99)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.os.Looper.loop(Looper.java:123)
02-22 12:22:50.256: E/AndroidRuntime(384):  at android.app.ActivityThread.main(ActivityThread.java:3683)
02-22 12:22:50.256: E/AndroidRuntime(384):  at java.lang.reflect.Method.invokeNative(Native Method)
02-22 12:22:50.256: E/AndroidRuntime(384):  at java.lang.reflect.Method.invoke(Method.java:507)
02-22 12:22:50.256: E/AndroidRuntime(384):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
02-22 12:22:50.256: E/AndroidRuntime(384):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
02-22 12:22:50.256: E/AndroidRuntime(384):  at dalvik.system.NativeStart.main(Native Method)

Обратите внимание, что причина java.lang.IndexOutOfBoundsException: index=1 count=0. Это будет означать, что количество страниц/элементов равно 0, а индекс, который я запрашиваю, равен 1. Ни одна из этих вещей не верна. Вот как я вызываю свой ViewPager и запрашиваю данную страницу:

ViewPager pager = (ViewPager) findViewById(R.id.ma_viewcontainer);
PAdapter adapter = new PAdapter();
pager.setAdapter(adapter);
pager.setCurrentItem(2);

Обратите внимание, что этот вызов не дает никаких ошибок и правильно устанавливает текущий элемент в средний элемент (индекс 1):

ViewPager pager = (ViewPager) findViewById(R.id.ma_viewcontainer);
PAdapter adapter = new PAdapter();
pager.setAdapter(adapter);
pager.setCurrentItem(1);

У меня есть количество 3 элементов в пейджере просмотра. Вот мой полный класс PAdapter, который расширяет класс PagerAdapter:

private class PAdapter extends PagerAdapter implements TitleProvider {

    private int COUNT = 3;

    private static final int SETTINGS_ACTIVITY = 0;
    private static final int MAIN_ACTIVITY = 1;
    private static final int FRIEND_LIST_ACTIVITY = 2;

    @Override
    public int getCount() {
        return COUNT;
    }

    @Override
    public Object instantiateItem(View collection, int position) {
        LinearLayout layout = new LinearLayout(getApplicationContext());
        LayoutInflater inflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        switch(position) {
        case MAIN_ACTIVITY :
            layout = (LinearLayout) inflater.inflate(R.layout.main, null, false);
            initMainLayout(layout);
            break;
        case SETTINGS_ACTIVITY :
            layout = (LinearLayout) inflater.inflate(R.layout.settings, null, false);
            initSettingsLayout(layout);
            break;
        case FRIEND_LIST_ACTIVITY :
            layout = (LinearLayout) inflater.inflate(R.layout.friend_list, null, false);
            initFriendListLayout(layout);
            break;
        }
        ((ViewPager)collection).addView(layout, position);
        return layout;
    }

    @Override
    public void destroyItem(View collection, int position, Object view) {
        ((ViewPager)collection).removeView((LinearLayout)view);
    }

    @Override
    public boolean isViewFromObject(View v, Object o) {
        return v == (LinearLayout)o;
    }

    @Override
    public void finishUpdate(View arg0) {
        //no need
    }

    @Override
    public void restoreState(Parcelable arg0, ClassLoader arg1) {
        //no need
    }

    @Override
    public Parcelable saveState() {
        return null;
    }

    @Override
    public void startUpdate(View arg0) {
        //no need
    }

    @Override
    public String getTitle(int position) {
        Resources res = getApplicationContext().getResources();
        switch(position) {
        case MAIN_ACTIVITY :
            return res.getString(R.string.app_name);
        case SETTINGS_ACTIVITY :
            return res.getString(R.string.settings);
        case FRIEND_LIST_ACTIVITY :
            return res.getString(R.string.friend_list);
        default :
            return null;
        }
    }
}

Строка ((ViewPager)collection).addView(layout, position); вызывает сбой.

Как видите, три предмета. Использование setCurrentItem() с параметром 0 или 1 прекрасно работает, но 2 вызывает эту странную ошибку. У меня закончились идеи, чтобы решить эту проблему ... к сожалению, ViewPager, похоже, находится в каких-то неизведанных водах Android. Если у кого-то есть понимание того, как решить эту проблему, это будет очень признательно. Спасибо!

РЕДАКТИРОВАТЬ: согласно предложению Шерифа, я попытался зарегистрировать количество детей с помощью collection.getChildCount() и получил следующий результат:

02-22 15:20:42.274: E/children count(645): count: 0
02-22 15:20:42.454: E/children count(645): count: 1
02-22 15:20:42.594: E/children count(645): count: 2

Это интересно. Это говорит мне о том, что он создает пустой PagerAdapter и добавляет их по одному. instantiateItem() вызывается 3 раза для трех видимых видов (в центре, слева и справа). Поэтому я добавил этот блок кода внутри метода instantiateItem():

if(((ViewPager)collection).getChildCount() ==  2) {
    ((ViewPager)collection).setCurrentItem(2);
}

Таким образом, только если счетчик установлен равным 2, он установит для страницы значение 2 (это хакерское решение, которое не полностью решает проблему, но его стоило попробовать). Я получил аналогичный стек ошибок, который сначала указывал на строку: ((ViewPager)collection).setCurrentItem(2);, затем ((ViewPager)collection).addView(layout, position);.

Надеюсь, это поможет дать некоторое представление.


person JMRboosties    schedule 22.02.2012    source источник
comment
if(((ViewPager) collection).getChildCount() == 2) { ((ViewPager) collection).setCurrentItem(2); } это означает, что представление будет создано и введено в коллекцию только в этом случае, в противном случае будет перерисовано с нуля, поэтому вы потеряете оптимизацию viewpager, сделанную для повторного использования представлений, а не перерисовки их с нуля.   -  person Shereef Marzouk    schedule 23.02.2012


Ответы (2)


Я не думаю, что вы можете просто сделать ((ViewPager)collection).addView(layout, position). Это зависит от вашего лимита страниц за пределами экрана, который, по-моему, по умолчанию равен 1. Я предполагаю, что вы используете только 3 представления, поэтому вы можете сделать что-то вроде viewPager.setOffscreenPageLimit(3); в своем `onCreate (или где бы вы ни разместили свой вызов), чтобы каждое представление не обновлялось каждый раз, когда вы его покидаете.

В нескольких уроках вы увидите, что ((ViewPager) collection).addView(view, 0); используется в instantiateItem(). Я довольно много работал с ViewPagers за последние несколько недель, и использование 0 в качестве позиции - все время - работает просто отлично.

person aimango    schedule 23.02.2012
comment
Это сделало это! Странно, что вы не установили для метода addView() фактическую позицию дочернего элемента, но я не буду сомневаться в этом! - person JMRboosties; 23.02.2012
comment
Я согласен, это странно, но так работает ViewPager. Я рад, что ваша проблема теперь решена :) - person aimango; 24.02.2012
comment
Так странно, это также решило мою проблему! - person Petro; 30.11.2014

Я вижу журнал сбоев, я вижу, что он падает при создании экземпляра элемента. Я не знаю, какая именно строка, потому что у меня нет ваших номеров строк

Но если бы я был игроком на ставках, я бы поспорил, что:

  ((ViewPager)collection).addView(layout, position);

Сбои при попытке добавить представление в позицию 1, когда в коллекции нет страниц. Возможно, проверьте collection.getchildcount() (возможно, имя метода неверно) и вставьте в max (позиция, количество)

то есть заменить позицию на:

count > position ? position : count

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

((ViewPager)collection).addView(layout, ((ViewPager)collection).getChildCount() > position ? position : ((ViewPager)collection).getChildCount())

p.s. Пишу с телефона извините за ужасное форматирование

Пожалуйста отметьте

 02-22 12:22:50.256: E/AndroidRuntime(384): at us.tagverse.pagertest.MasterActivity$PAdapter.instantiat 

MasterActivity.java:518

Число в конце строки я скопировал и тогда узнаешь какая это строка и только тогда ты узнаешь в какой строке произошел сбой

РЕДАКТИРОВАТЬ: P.S. о вашем решении

Я думаю, что ваше решение устанавливает текущий элемент только после того, как 3 страницы были созданы экземпляром элемента, но моя строка заставит его работать, даже если они не будут созданы.

person Shereef Marzouk    schedule 22.02.2012
comment
Извините, да, забыл указать. Эта линия действительно вызывает сбой. Я обновлю вопрос, чтобы отразить это. - person JMRboosties; 23.02.2012
comment
Я придумал это решение и попробовал его, см. мой первоначальный вопрос о результатах. - person JMRboosties; 23.02.2012
comment
Я рад, что это сработало, если мой ответ помог вам достичь вашей цели, не могли бы вы отметить его как правильный ответ? - person Shereef Marzouk; 23.02.2012
comment
((ViewPager)collection).addView(layout, ((ViewPager)collection).getChildCount() › position ? position : ((ViewPager)collection).getChildCount()) это решение, которое я добавил первым, но оно было плохо отформатировано, потому что я добавил с телефона - person Shereef Marzouk; 23.02.2012
comment
В любом случае, мистер JMRboosties, даже если решение, которое я изначально опубликовал в ответе, не сработало, разве мой ответ не привел вас к решению? прокомментируйте свое решение внизу моего ответа - person Shereef Marzouk; 23.02.2012
comment
@Shereef, для этого и нужны голоса. Если ответ помечен как правильный, он должен быть завершен в своем решении, чтобы другие люди могли использовать его позже. - person Reno; 23.02.2012
comment
@Reno ((ViewPager)collection).addView(layout, ((ViewPager)collection).getChildCount() › position ? position : ((ViewPager)collection).getChildCount()) Работает просто отлично, но ответ аиманго, безусловно, лучше, но мой был здесь первым, однако я не жалею, что айманго дал правильный ответ, его ответ лучше :) - person Shereef Marzouk; 26.02.2012