Фрагмент в ViewPager с использованием FragmentPagerAdapter остается пустым при втором просмотре


98

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

У меня есть один конкретный фрагмент, который представляет собой список предметов. Если пользователь выбирает один из элементов в этом списке, открывается другой фрагмент, который содержит окно просмотра, которое прокручивается по горизонтали между всеми элементами в списке в предыдущем фрагменте. Это прекрасно работает.

Viewpager использует FragmentPagerAdapter для отображения элементов.

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

Почему окно просмотра появляется только в первый раз?

FragmentPagerAdapter:

public class ViewPagerAdapter extends FragmentPagerAdapter {
    Cursor mCursor;

    public ViewPagerAdapter(FragmentManager fm, Cursor c) {
        super(fm);
        mCursor = c;
    }

    public void changeCursor(Cursor c) {
        mCursor = c;
        this.notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        if (mCursor == null) return 0;
        else return mCursor.getCount();
    }

    @Override
    public Fragment getItem(int position) {
        mCursor.moveToPosition(position);
        return TeamCardFragment.newInstance(mCursor, position);
    }
}

PagerFragment:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);

    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);

    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();

    return mView;
}

private class setAdapterTask extends AsyncTask<Void, Void, Void> {
    protected Void doInBackground(Void... params) {
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        mViewPager.setAdapter(mAdapter);
        mViewPager.setCurrentItem(mCursorPosition);
    }
}

Ответы:


221

Я была такая же проблема. Изменение родительского класса моего PageAdapter с android.support.v4.app.FragmentPagerAdapterдля android.support.v4.app.FragmentStatePagerAdapterрешения моей проблемы с ViewPagerотображением "во второй раз"!


2
Без шуток? У меня больше нет этого кода, иначе я бы его протестировал. Возможно, этот ответ поможет кому-нибудь другому.
howettl

10
Какой человек! Я искал это решение несколько дней! Большое спасибо, человек, работает как шарм. Но разработчик во мне спрашивает, какое влияние окажет это изменение? Я имею в виду, почему это не работало раньше и почему в StatePagerAdapter
Ананд Сайнат

1
также вам нужно @Override public int getItemPosition (объект объекта) {return POSITION_NONE; }
Хелин Ван

1
У меня тоже сработало. Вот ссылка. Кажется, что сохраняется состояние фрагмента, в чем вся разница. developer.android.com/reference/android/support/v4/app/…
Tjaart

1
По совпадению, это работает, правильный ответ - ответ @Daniel F. В любом случае, для удобства комментаторов здесь разница между FragmentPagerAdapterи FragmentStatePagerAdapterзаключается в том, что первый больше подходит для нескольких страниц, он сохраняет все фрагменты в памяти, обеспечивая лучшую производительность при переключении страниц, в то время как последний больше подходит для многих страниц, он уничтожает фрагменты, сохраняя только их состояние, это более эффективно с точки зрения памяти, но немного медленнее при переключении страниц.
Cristina De Rito

87

Мне удалось решить эту проблему путем замены getFragmentManager()с getChildFragmentManager()в родительском фрагменте. Этот родительский фрагмент создавал экземпляр android.support.v4.app.FragmentPagerAdapter , чтобы содержать перелистываемые (скользящие) фрагменты, для чего требуется диспетчер фрагментов в конструкторе. Этому конструктору я передал возвращаемое значение getChildFragmentManager().

Ссылка hackbod была ключевой ( https://developer.android.com/about/versions/android-4.2.html#NestedFragments ), которая была найдена в этом посте Фрагменты внутри фрагментов

Чтобы вложить фрагмент, просто вызовите getChildFragmentManager()фрагмент, в который вы хотите добавить фрагмент. Это возвращает FragmentManager, который вы можете использовать, как обычно, из действия верхнего уровня для создания транзакций фрагментов.


Спасибо ... у меня была аналогичная проблема при попытке повторно создать экземпляр представления скользящих вкладок после onresume (), который содержал fragmentpageradapter ... учебник, который я использовал, был с 2016 года, и мне все еще нужно было изменить его на fragmentstatepageradapter, чтобы получить его работай. Хотел бы я знать, ПОЧЕМУ.
Nerdy Bunz

этот ответ сэкономил мне много времени. Потому что только использование не FragmentStatePagerAdapterрешает поставленный здесь вопрос. вместе с FragmentStatePagerAdapterродительским фрагментом YourAdapter adapter = new YourAdapter (getChildFragmentManager()); должен быть добавлен
MMK

17

для меня я должен был вызвать это в моем окне просмотра:

myViewPager.setSaveFromParentEnabled(false);

У меня была проблема, когда окно просмотра не обновлялось, и все, что я видел, было пустым белым экраном, на котором должны быть фрагменты. Я проходил через getChildFragmentManager, но это не помогло.


1
Почему это сработало? Это устранило мою проблему, но я понятия не имею, почему.
ClayHerendeen

Я удалил это из своего кода сейчас. Диспетчер фрагментов был причиной проблемы. Попробуйте переключаться между getchildfragmentmanager и getfragmentmanager
j2emanue 01

Я это уже пробовал. У меня есть вложенные вкладки с ViewPager, в которых отключено смахивание. Я знаю, что это плохой дизайн, но его клиенты хотят, а не мои. Я использую childFragmentManager для панели вкладок верхнего уровня. Переключение панели вкладок / окна просмотра нижнего уровня, похоже, не решило проблему. Я полагаю, что пока буду придерживаться setSaveFromParentEnabled (false), поскольку он работает.
ClayHerendeen 01

Используете ли вы последнюю библиотеку поддержки
j2emanue

2
Я столкнулся с той же проблемой за последние 2 дня .. Ваше решение сработало для меня. Спасибо !
brijexecon

11

В моем конкретном случае, когда я использовал CoordinatorLayout с AppBarLayout и ViewPager, для меня это решило удаление android: fitsSystemWindows = "true" из моих свойств AppBarLayout xml .

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


3
Ой ... Я почти собирался сдаться с этой проблемой. Ты сделал мне долбаный день! Господи, гугл, что за ошибка с AppBarLayout? Я просмотрел почти сотню страниц и потратил кучу часов на отладку, безуспешно пытаясь решить эту проблему. Я очень благодарен, что мне наконец удалось решить проблему с вашим комментарием. Большое спасибо! PS: Я был в таком отчаянии, что даже создал проблему в AOSP: code.google.com/p/android/issues/… XD
Гиллем Рока,

Спасибо за подсказку. По крайней мере, это помогло нам решить проблему. Сейчас мы пытаемся найти вариант сделать его полноэкранным
Пареш Майани

Вы палочка-выручалочка! Я совершенно не понимал, почему у меня возникла эта проблема, и до сих пор не понимал, почему это сработало!
нанду

10

У меня была такая же проблема, из-за которой я изменил адаптер с FragmentPagerAdapterна FragmentStatePagerAdapterи getFragmentManager()в родительском фрагменте наgetChildFragmentManager()

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


4

Попробуйте поставить setOffscreenPageLimit (int limit)на родительский ViewPager.

mViewPager.setOffscreenPageLimit(totalPages-1);

Это сработало для меня как шарм.

В моем случае внутри был фрагмент TabLayoutсViewPager.

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


1
Хороший ответ. Мне это помогло.
Thirumalvalavan


1

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


вы можете попробовать удалить функцию isViewFromObject (View view, Object object)
Mina Samy

Должен быть способ получше ....: / хотя чем больше я вникаю в Android, тем менее зрелым я его понимаю.
StackOverflowed

1
Вложенные фрагменты не поддерживаются , поэтому повторная реализация со стандартным представлением кажется правильным решением.
Sylphe

Я борюсь с подобной проблемой. Я попытался использовать PagerAdapter вместо FragmentAdapter, но столкнулся с той же проблемой. Пожалуйста, помогите мне!
Gaurav Arora

Если вы хотите использовать вложенные фрагменты, вы можете использовать адаптер, который я предоставил в этом ответе: stackoverflow.com/questions/7700226/…
Slickelito

1

У меня была такая же проблема на Xamarin Android с пустым экраном во второй раз ... Установка следующего исправила это для меня.

viewPager.SaveFromParentEnabled = false;

0

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

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);
    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);
    initViewPagerAdapter();
    return mView;
}
private void initViewPagerAdapter(){
    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();
}

@Override
public void onResume(){
    super.onResume();
    initViewPagerAdapter();
}

0

У меня было то же самое, во второй раз, когда я вызываю адаптер пейджера, дочернее представление возвращает исключение NullPointerException. И изменение адаптера в FragmentStatePagerAdapter тоже решает мою проблему.


0

Изменение FragmentPagerAdapterв FragmentStatePagerAdapter использовании getChildFragmentManager()вместоgetFragmentManager()

getChildFragmentManager()- потому что, согласно документации, он вернет частный FragmentManager для размещения и управления фрагментами внутри этого фрагмента. Тем временем getFragmentManager()вернет FragmentManager для взаимодействия с фрагментами, связанными с этим действием.


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.