Фрагмент у 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 (Object object) {return POSITION_NONE; }
Хелін Ван

1
Працював і для мене. Ось посилання. Здається, збережеться фрагмент стан, що робить все різницею. developer.android.com/reference/android/support/v4/app/…
Tjaart

1
Це збіг обставин, правильна відповідь - це @Daniel F. У всякому разі, для зручності коментаторів тут, різниця між FragmentPagerAdapterі FragmentStatePagerAdapterв колишньому істоту більш підходить для декількох сторінок, вона зберігає всі фрагменти в пам'яті , таким чином , мають найкращі характеристики на комутаторі сторінки, в той час як останнє більш підходять для багатьох сторінок, він руйнує фрагменти, зберігаючи лише їх стан, він ефективніше пам’яті, але трохи повільніше перемикання сторінок.
Крістіна Де Ріто

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

Я вже пробував це. Я вклав кожну вкладку з ViewPagers, де вимкнено перенесення. Я знаю, що це поганий дизайн, але його клієнти не хочуть. Я використовую childFragmentManager для вкладки верхнього рівня. Бореться за панель вкладок нижнього рівня / viewpager, здається, не вирішила проблему. Я припускаю, що зараз я буду дотримуватися setSaveFromParentEnabled (false), оскільки він працює.
ClayHerendeen

Використовуєте останню бібліотеку підтримки
j2emanue

2
Я стикався з тим же питанням, що і останні два дні. Ваше рішення працювало на мене. Дякую !
brijexecon

11

У моєму дуже конкретному випадку, коли я використовував CoordinatorLayout з AppBarLayout та ViewPager, це вирішило для мене вилучення андроїда: fitsSystemWindows = "true" із моїх xml-властивостей AppBarLayout .

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


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

Дякую за підказку. Принаймні, це допомогло нам у вирішенні питання. Зараз ми намагаємося знайти варіант для створення його на весь екран
Paresh Mayani

Ви рятувальник! Я був абсолютно незрозумілий, чому у мене виникло це питання, і досі незрозуміло, чому він працює!
нанду

10

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

Причина цього FragmentStatePagerAdapterкорисна для зберігання великої кількості сторінок, а пам’яті, пов’язаної з кожною відвідуваною сторінкою, менше, оскільки вона зберігає лише збережений стан фрагмента, поки сторінка не відображається. Це зменшує накладні витрати при переключенні між фрагментами.


4

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

mViewPager.setOffscreenPageLimit(totalPages-1);

Це працювало для мене як шарм.

У моєму випадку у мене був фрагмент всередині TabLayout зViewPager.

І ще ViewPagerвсередині цього фрагмента. Перший раз все нормально працює, але коли я міняю вкладку і повертаюсь назад, частина мого фрагмента втрачається.


1
Хороша відповідь. Мені це допомагає.
Thirumalvalavan


1

Ми подолали це шляхом повторної реалізації елементів пейджерного виду перегляду як стандартних подань, а не фрагментів, та відповідно змінивши адаптер.


ви можете спробувати видалити функцію isViewFromObject (Перегляд подання, об'єкт)
Міна Самі

Треба бути кращим способом ....: / хоча чим більше я копаюся в Android, тим менш зрілим я усвідомлюю, що це.
StackOverflowed

1
Вкладені фрагменти не підтримуються , тому повторна реалізація зі стандартним переглядом здається хорошим шляхом.
Сільфе

Я борюся з подібним питанням. Я спробував використати 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.