Android - tabbedActivity с динамическим количеством вкладок

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

java.lang.IllegalStateException: PagerAdapter приложения изменил содержимое адаптера без вызова PagerAdapter#notifyDataSetChanged! Ожидаемое количество элементов адаптера: 3, найдено: 2 Идентификатор пейджера: abm.ant8.sotgtests:id/container Класс пейджера: class android.support.v4.view.ViewPager Проблемный адаптер: class abm.ant8.sotgtests.MainActivity$SectionsPagerAdapter

Когда я комментирую this.notifyDataSetChanged() (отмечено ЗДЕСЬ), в обоих случаях происходит сбой. Вот мой код PagerAdapter (я использую пакет поддержки v4):

public class SectionsPagerAdapter extends FragmentStatePagerAdapter {

        public SectionsPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            mExplanationFragment = ExplanationFragment.newInstance();
            mQuestionFragment = QuestionFragment.newInstance(totalNoOfQuestions);
            if (mode == LEARNING_MODE) {
                mRulesFragment = RulesFragment.newInstance();
            }
            Fragment fragment;

            if (mode == TESTING_MODE) {
                if (position == 1) {
                    fragment = mExplanationFragment;
                } else {
                    fragment = mQuestionFragment;
                }
            } else {
                if (position == 2) {
                    fragment = mExplanationFragment;
                } else if (position == 1){
                    fragment = mQuestionFragment;
                } else  {
                    fragment = mRulesFragment;
                }
            }

            //this.notifyDataSetChanged(); HERE
            return fragment;
        }

        @Override
        public int getCount() {
            if (mode == TESTING_MODE) {
                return 2;
            } else {
                return 3;
            }
        }
        //...
        @Override
        public int getItemPosition(Object object) {
            return POSITION_NONE;
        }
    }
}

Это уже после применения подсказок из этой темы SO, другие выглядели очень похоже. Является ли этот подход (взятый непосредственно из мастера Android Studio) правильным для этой ситуации? Похоже, что определение начальной вкладки по умолчанию как средней, а не первой, также будет проблемой (но это, конечно, для другого вопроса, после того, как я решу эту проблему).

РЕДАКТИРОВАТЬ: в качестве решения грубой силы я думаю просто скопировать текущую активность и слегка изменить ее, чтобы она не была активностью, вызываемой с дополнительными намерениями, а вызывала разные действия. Поскольку большая часть необходимой функциональности уже реализована (и большая часть ее фрагментарна), это, безусловно, самый быстрый способ. Чтобы сохранить модульность и чистоту, я могу просто провести рефакторинг и переместить методы, общие для обоих Activity, в отдельный класс.


person Antek    schedule 18.11.2015    source источник
comment
как ваша ошибка говорит: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged,   -  person Shayan Pourvatan    schedule 18.11.2015
comment
Кроме того, замена getCount() на FragmentPagerAdapter или FragmentStatePagerAdapter вряд ли сработает. По крайней мере, мне никогда не везло с этим. Я закончил писать свою собственную реализацию PagerAdapter.   -  person CommonsWare    schedule 18.11.2015
comment
так желательно ли тогда добавлять и удалять вкладки с помощью ActionBar? Собственно, где я должен вызывать notifyDataSetChanged()? Я попытался сделать это, как показано в коде выше, но без особого успеха;)   -  person Antek    schedule 18.11.2015


Ответы (1)


В итоге я создал два отдельных адаптера, вызывая их в хостинговой активности:

if (mode == LEARNING_MODE) {
    mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
    // Set up the ViewPager with the sections adapter.
    mViewPager = (ViewPager) findViewById(R.id.container);
    mViewPager.setAdapter(mSectionsPagerAdapter);
    mViewPager.setCurrentItem(1);
} else {
    mTwoSectionsPagerAdapter = new TwoSectionsPagerAdapter(getSupportFragmentManager());
    // Set up the ViewPager with the sections adapter.
    mViewPager = (ViewPager) findViewById(R.id.container);
    mViewPager.setAdapter(mTwoSectionsPagerAdapter);
}

Таким образом, эти PagerAdapters отличались только getCount() и, конечно же, предоставлением правильных фрагментов в соответствующих местах (метод getItem()).

person Antek    schedule 05.02.2016