Представление фрагмента в 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.
Пройдите весь этот код в этом классе, и вы увидите, как я динамически загружаю фрагменты, каждый раз 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.