Представление фрагмента в ViewPager не восстанавливается при возобновлении

У меня есть настройки вкладок ActionBar. Он состоит из 4 вкладок. Все хорошо, пока я не уеду от TabbedFragment и возвращаться обратно.

Я создаю вкладки, как это:

  @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final ActionBar actionBar = getActionBar();

        tabs = Lists.newArrayList();
        tabs.add(new TabDefinition<>("Tab 1"));
        tabs.add(new TabDefinition<>("Tab 2"));
        tabs.add(new TabDefinition<>("Tab 3"));
        tabs.add(new TabDefinition<>("Tab 4"));


        for (TabDefinition tab : tabs) {
            actionBar.addTab(actionBar.newTab()
                .setText(tab.text)
                .setTag(tab.tag)
                .setTabListener(this));
        }
    }

И инициализировать адаптер так:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.layout.paging_tab_container, container, false);
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    viewPager = (ViewPager) view.findViewById(R.id.pager);

    viewPager.setAdapter(new FragmentStatePagerAdapter(getFragmentManager()) {

        @Override
        public Fragment getItem(int position) {
            return tabs.get(position).fragment;
        }

        @Override
        public int getCount() {
            return tabs.size();
        }
    });

    viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
        @Override
        public void onPageSelected(int position) {
            getActionBar().setSelectedNavigationItem(position);
        }
    });

    viewPager.setCurrentItem(getActionBar().getSelectedNavigationIndex(), true);
}

Возвращаясь к TabbedFragment выбранная вкладка и 1 рядом с ней не будет иметь никакого содержимого. Просто пустой вид. Но если я выберу текущий + 2, содержимое фрагмента загружается. И затем, возвращаясь к этому первому фрагменту, содержимое перезагружается.
Например, у меня есть вкладки A, B, C, D. Перед уходом TabbedFragment Я выбрал вкладку А. При возвращении в TabbedFragment Я до сих пор на вкладке А, но она пуста. Так же, как вкладка B.
Но при выборе вкладки C она создается и загружается. Возвращаясь к вкладке А, он воссоздается.

В чем может быть проблема здесь?

6 ответов

Решение

Через некоторое время снова столкнулся с той же проблемой, поэтому обновил этот вопрос. Если вы используете FragmentStatePagerAdapter вы должны предоставить FragmentManager с помощью getChildFragmentManager() вместо getFragmentManager(), См. Выпуск 55068: ViewPager не обновляет дочерние фрагменты при обратной навигации через backstack.

Хорошо, так при использовании FragmentStatePagerAdapter ваши фрагменты будут уничтожены, когда вы перейдете больше, чем один фрагмент прочь, так как по умолчанию offScreenPageLimit по умолчанию равно 1, как указано выше.

Обычно этот класс используется для деятельности, которая имеет очень большой набор Fragmentsт.е. приходится пролистывать большое количество просмотров. Если ваше приложение не требует больше, чем скажем 3-4 вкладки, я бы предложил использовать FragmentPagerAdapter вместо этого, а затем указав для offScreenPageLimit что-то вроде 3, так что если вы перейдете к 4-й вкладке, все 3 вкладки до этого все еще будут в памяти.

Вот пример кода для проекта на github, который я создал, иллюстрирующий, как динамически загружать фрагменты, если вы не хотите добавлять это offScreenPageLimit.

https://github.com/lt-tibs1984/InterfaceDemo/blob/master/src/com/divshark/interfacedemo/InterfaceDemoMain.java

Пройдите весь этот код в этом классе, и вы увидите, как я динамически загружаю фрагменты, каждый раз ViewPager скользит Особенно в нижней части.

Вы можете скачать этот код и использовать его в качестве тестовой базы для того, что вы хотите сделать. Попробуйте добавить setOffScreenPageLimit(2) в метод onCreate() для viewPager и обратите внимание на другое поведение. Чтобы проверить поведение, отредактируйте текст во фрагменте 1. Перейдите Away и вернитесь назад, с этим набором или нет. Когда он будет установлен, вы увидите, что текст фрагмента остается тем, на что вы его изменили, поскольку фрагмент никогда не воссоздается.

Пожалуйста, предоставьте дополнительные вопросы, если они у вас есть.

Удачи

ОБНОВИТЬ

private static final String [] fragmentClasses = {"com.example.project.YourFragment1","com.example.project.YourFragment2","com.example.project.YourFragment3"};



 viewPager.setAdapter(new FragmentStatePagerAdapter(getFragmentManager()) {

    @Override
    public Fragment getItem(int position) {

       Fragment fragmentAtPosition = null;

       // $$$$ This is the Important Part $$$$$
       // Check to make sure that your array is not null, size is greater than 0 , current position is greater than equal to 0, and position is less than length
       if((fragmentClasses != null) && (fragmentClasses.length > 0)&&(position >= 0)&& (position < fragmentClasses.length))
        {
       // Instantiate the Fragment at the current position of the Adapter
        fragmentAtPosition = Fragment.instantiate(getBaseContext(), fragmentClasses[position]);
        fragmentAtPosition.setRetainInstance(true);

       }

        return fragmentAtPosition;
    }

    @Override
    public int getCount() {
        return fragmentClasses.length;
    }
});

Думаю, проблема существует во фрагментах, которые вы используете в качестве вкладок. Кажется, что они ничего не показывают, когда они возобновляются (см. Жизненный цикл фрагмента). "Странная" проблема, что только выбранная в данный момент вкладка +/-1 пуста, заключается в том, offScreenPageLimit вашей ViewPager по умолчанию 1 Все вкладки выше этого порога воссоздаются.

Поэтому увеличение значения в вашем случае приведет к тому, что все ваши вкладки будут казаться пустыми после возобновления работы. Проверьте в коде фрагмента, какие методы жизненного цикла вы используете для раздувания макета, установки адаптеров и т. Д., Потому что именно это вызывает у вас проблемы.

Я предполагаю, что это происходит потому, что при загрузке фрагмента Android загружает текущий и текущий +1, если вы отлаживаете, вы не увидите onPause, вызываемого для следующего следующего фрагмента.

Вы можете перезагрузить контент программным способом в методе onTabChanged() метода TabHost.OnTabChangeListener.

После долгих исследований это сработало для меня. У меня сложный макет с 3 вкладками во фрагменте, который переключается на другие фрагменты. Я понял, что ViewpagerAdapter будет сохранять состояние, даже если вы нажмете кнопку домой. Моя проблема была в том, что переключение вперед и назад приводило к обнулению дочерних фрагментов элементов интерфейса и вылету. Ключ к не new из вашего ViewPagerAdapter, Добавление нулевой проверки для адаптера работало для меня. Также обязательно выделите setOffscreenPageLimit() для ваших нужд. Кроме того, из того, что я понимаю setRetainInstance(true); не следует использовать для фрагментов, которые имеют пользовательский интерфейс, он предназначен для фрагментов без заголовка.

Во фрагменте, который содержит ваши вкладки:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_tab, container, false);
    tabLayout = (TabLayout) view.findViewById(R.id.tablayout);
    viewPager = (ViewPager) view.findViewById(R.id.viewPager);

    //Important!!! Do not fire the existing adapter!!
    if (viewPagerAdapter == null) {
        viewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager());
        viewPagerAdapter.addFragments(new AFragment(), "A");
        viewPagerAdapter.addFragments(new BFragment(), "B");
        viewPagerAdapter.addFragments(new CFragment(), "C");
    }
    //Allocate retention buffers for three tabs, mandatory
    viewPager.setOffscreenPageLimit(3);
    tabLayout.setupWithViewPager(viewPager);
    viewPager.setAdapter(viewPagerAdapter);

    return view;
}

Или более просто при переходе назад к tabbedfragment (при условии, что вы используете намерение, а фрагмент находится внутри действия) используйте:

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

Это сохраняет исходную активность и перемещает ее в верхнюю часть стека, а не воссоздает ее, поэтому вам никогда не нужно пересматривать viewPager.

Другие вопросы по тегам