Фрагмент у 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.