Отображать фрагмент просмотра в фрагменте

У меня есть фрагмент, который содержит ViewPager. ViewPager связан с адаптером, который содержит набор фрагментов.

При загрузке родительского фрагмента мне встречается IllegalStateException с сообщением: java.lang.IllegalStateException: Recursive entry to executePendingTransactions .

Некоторые исследования привели меня к выводу, что система не может отображать фрагменты внутри другого фрагмента. ОДНАКО, похоже, есть некоторые указания на то, что это можно сделать именно с использованием ViewPager ( ошибка в ViewPager, использующая его с другим фрагментом ).

Фактически, если я добавлю кнопку в родительский фрагмент, который вызывает mPager.setAdapter(mAdapter) на моем ViewPager при нажатии, ViewPager успешно загружается. Это не идеально.

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

Есть ли способ отложить настройку адаптера на ViewPager до завершения транзакции фрагмента?

Вот мой родительский фрагмент кода:

  @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mView = inflater.inflate(R.layout.team_card_master, container, false); mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager); final Button button = (Button)mView.findViewById(R.id.load_viewpager_button); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mViewPager.setAdapter(mAdapter); button.setVisibility(View.GONE); } }); mAdapter = new ViewPagerAdapter(getFragmentManager()); // mViewPager.setAdapter(mAdapter); return mView; } 

И адаптер:

 public class ViewPagerAdapter extends FragmentPagerAdapter { public ViewPagerAdapter(FragmentManager fm) { super(fm); } @Override public int getCount() { if (mCursor == null) return 0; else return mCursor.getCount(); } @Override public Fragment getItem(int position) { Bundle b = createBundle(position, mCursor); return TeamCardFragment.newInstance(b); } } 

Используйте AsyncTask для установки адаптера для viewPager. Меня устраивает. AsyncTask должен сделать исходный фрагмент завершенным его переходом. А затем мы идем с фрагментами viewPager, в основном, чтобы избежать рекурсии.

  @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mView = inflater.inflate(R.layout.team_card_master, container, false); mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager); final Button button = (Button)mView.findViewById(R.id.load_viewpager_button); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mViewPager.setAdapter(mAdapter); button.setVisibility(View.GONE); } }); mAdapter = new ViewPagerAdapter(getFragmentManager()); 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); } } 

Jords, я думаю, вы можете использовать FragmentStatePagerAdapter вместо FragmentPageAdapter . Он удалит фрагменты для вас.

PS. Извините за использование ответа вместо комментария, но моя репутация слишком низкая.

Я просто столкнулся с этой проблемой. У меня был Fragment который должен был разместить ViewPager of Fragments . Когда я собрал еще один Fragment поверх моего ViewPagerFragment , а затем ударил, я бы получил IllegalStateException . После проверки журналов (при укладке нового Fragment ) я обнаружил, что мой ViewPagerFragment будет использовать методы жизненного цикла, чтобы остановить и уничтожить, однако его дочерние Fragments в ViewPager останутся в onResume . Я понял, что Fragments детей должен управляться FragmentManager для ViewPagerFragment , а не FragmentManager Activity .

В то время я понял, что ответы выше были направлены на ограничение ограничений Fragments не могут иметь детей. Однако теперь, когда в последней библиотеке поддержки есть поддержка для вложения Fragment , вам больше не нужно взламывать настройку адаптера для вашего ViewPager , и передача getChildFragmentManager() – это все, что вам нужно. До сих пор это отлично работало для меня.

 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mView = inflater.inflate(R.layout.team_card_master, container, false); mViewPager = (ViewPager) mView.findViewById(R.id.team_card_master_view_pager); mAdapter = new ViewPagerAdapter(getChildFragmentManager()); mViewPager.setAdapter(mAdapter); return mView; } 

Я использовал Handler.post() для установки адаптера вне транзакции исходного фрагмента:

 @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mHandler.post(new Runnable() { @Override public void run() { mViewPager.setAdapter(mAdapter); } }); } 

Я столкнулся с этой проблемой при попытке инициализировать адаптер viewPager на вкладке TabIndicator в ViewCreated. Прочитав об этом в сети, я понял, что это может быть только потому, что фрагмент еще не был добавлен в действие. Поэтому я переместил код инициализации в onStart () фрагмента, это должно решить вашу проблему. Но не для меня, я все еще получал такую ​​же проблему снова.

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

При загрузке родительского фрагмента мне встречается исключение IllegalStateException с сообщением: java.lang.IllegalStateException: рекурсивная запись в executePendingTransactions.

Некоторые исследования привели меня к выводу, что система не может отображать фрагменты внутри другого фрагмента. ОДНАКО, похоже, есть некоторые указания на то, что это можно сделать именно с использованием ViewPager (ошибка в ViewPager, использующая его с другим фрагментом ).

Set Id для ViewPager явно.

  @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mView = inflater.inflate(R.layout.team_card_master, container, false); mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager); mViewPager.setId(100); final Button button = (Button)mView.findViewById(R.id.load_viewpager_button); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mViewPager.setAdapter(mAdapter); button.setVisibility(View.GONE); } }); mAdapter = new ViewPagerAdapter(getFragmentManager()); mViewPager.setAdapter(mAdapter); return mView; } 

Вы можете использовать id в своих xml-ресурсах вместо магического номера 100.

 <resources> <item name="Id_For_ViewPager" type="id"/> </resources> 

И setId (R.Id_For_ViewPager).

Подробнее см. Источник FragmentManager.java.

https://github.com/android/platform_frameworks_support/blob/master/v4/java/android/support/v4/app/FragmentManager.java#L900

Или см. Эту страницу (японский). Первоначальная идея от нее, собственно, и не от меня. http://y-anz-m.blogspot.jp/2012/04/androidfragment-viewpager-id.html

Используя этот блестящий пост Томаса Амсслера: http://tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part-ii.html

Iv'e создал адаптер, который можно использовать для создания всех типов фрагментов. Сам адаптер выглядит следующим образом:

 public abstract class EmbeddedAdapter extends FragmentStatePagerAdapter { private SparseArray<WeakReference<Fragment>> mPageReferenceMap = new SparseArray<WeakReference<Fragment>>(); private ArrayList<String> mTabTitles; public abstract Fragment initFragment(int position); public EmbeddedAdapter(FragmentManager fm, ArrayList<String> tabTitles) { super(fm); mTabTitles = tabTitles; } @Override public Object instantiateItem(ViewGroup viewGroup, int position) { mPageReferenceMap.put(Integer.valueOf(position), new WeakReference<Fragment>(initFragment(position))); return super.instantiateItem(viewGroup, position); } @Override public int getCount() { return mTabTitles.size(); } @Override public CharSequence getPageTitle(int position) { return mTabTitles.get(position); } @Override public Fragment getItem(int pos) { return getFragment(pos); } @Override public void destroyItem(ViewGroup container, int position, Object object) { super.destroyItem(container, position, object); mPageReferenceMap.remove(Integer.valueOf(position)); } public Fragment getFragment(int key) { WeakReference<Fragment> weakReference = mPageReferenceMap.get(key); if (null != weakReference) { return (Fragment) weakReference.get(); } else { return null; } } @Override public int getItemPosition(Object object) { return POSITION_NONE; } 

}

Чтобы использовать адаптер, вам нужно будет сделать следующее:

 private void setAdapter() { if(mAdapter == null) mAdapter = new EmbeddedAdapter(getActivity().getSupportFragmentManager(), mTabTitles) { @Override public Fragment initFragment(int position) { Fragment fragment; if(position == 0){ // A start fragment perhaps? fragment = StartFragment.newInstance(mBlocks); }else{ // Some other fragment fragment = PageFragment.newInstance(mCategories.get((position))); } return fragment; } }; // Have to set the adapter in a handler Handler handler = new Handler(); handler.post(new Runnable() { @Override public void run() { mViewPager.setVisibility(View.VISIBLE); mPagerTabStrip.setVisibility(View.VISIBLE); mAdapter.notifyDataSetChanged(); } }); } 

Обратите внимание, что все фрагменты используют:

 setRetainInstance(true); 

Согласно документации: https://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager ()

Если вы хотите управлять фрагментом вложенности, вы должны использовать getChildFragmentManager вместо getFragmentManager .

Intereting Posts
Запретить мое аудио приложение с помощью NuPlayer на Android Lollipop 5.x? Воспроизведите локальный файл m3u8 на Android-дисплее, показывая, что setDataSourceFD не удалось: status = 0x80000000 Синтетический и пользовательский макет Kotlin в DialogFragment Маркер Google Maps исчез только после увеличения на Android Android-атрибут макета Android android: layout_toLeftOf WARN / SoundPool образец 2 не ГОТОВ Как анимировать один элемент списка слоев Открыть список контактов, чтобы выбрать контакт, или добавить новый Используя Android AudioTrack для объединения байтов звуковых образцов, создает шум Как открыть файл в необработанной папке на Android Можете ли вы запрашивать разрешения синхронно в модели разрешений на запуск приложений Android Marshmallow (API 23)? Извлечение значков приложений xhdpi из packageManager? Использование плагинов с CLI Как я могу изменить –android-платформу в Qt Creator, чтобы не быть андроидом – 1 в режиме отладки? Android Разница между handler.postAtTime и handler.postDelayed