在片段中显示片段viewpager

我有一个包含ViewPager的片段。 ViewPager与包含一组片段的适配器相关联。

加载父片段后,遇到IllegalStateException ,消息: java.lang.IllegalStateException: Recursive entry to executePendingTransactions

一些研究使我得出这样一个结论:系统无法在另一个片段中显示片段,但是似乎有一些迹象表明,使用ViewPager(ViewPager中的一个bug使用它与其他片段 )。

事实上,如果我按下的button添加到我的父代片段,当我的ViewPager按下时调用mPager.setAdapter(mAdapter) ,ViewPager成功加载。 这并不理想。

这个问题必然与片段生命周期有关。 因此,我的问题是:有没有人find解决这个问题的办法,如果是的话,怎么办?

有没有办法延迟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的片段,基本上避免了recursion。

  @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 ,需要主办Fragments ViewPager 。 当我在ViewPagerFragment顶部堆叠另一个Fragment ,然后回来,我会得到一个IllegalStateException 。 在检查日志(堆叠一个新的Fragment )之后,我发现ViewPagerFragment会通过其生命周期方法停止和销毁,但ViewPager中的子Fragments仍然保留在onResume 。 我意识到子Fragments应该由ViewPagerFragmentFragmentManagerpipe理,而不是ActivityFragmentManager

当时我明白了,上面的答案是为了解决Fragments的局限性,不能有孩子的Fragments 。 但是,现在最新的支持库支持Fragment嵌套,您不再需要为ViewPager设置适配器, 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); } }); } 

尝试在ViewCreated上的TabIndicator上初始化viewPager适配器时遇到此问题。 在网上阅读后,我意识到这可能只是因为片段还没有添加到活动中。 所以我将初始化代码移动到片段的onStart(),这应该解决您的问题。 但是对我来说,我还是得到了同样的问题。

但那是因为在我的代码中,我试图通过显式调用executePendingTransactions()来绕过正常的asynchronous执行,

加载父片段后,遇到IllegalStateException,消息:java.lang.IllegalStateException:recursion进入executePendingTransactions。

一些研究使我得出这样一个结论:系统无法在另一个片段中显示片段,但是似乎有一些迹象表明,使用ViewPager(ViewPager中的一个bug使用它与其他片段)。

显式地为ViewPager设置Id。

  @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; } 

你可以在你的xml资源中使用id而不是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

Thomas Amssler使用这个精彩的文章: http ://tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part-ii.html

Iv'e创build了一个可用于创build所有types碎片的适配器。 适配器本身看起来像这样:

 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()

如果你想pipe理嵌套片段,你必须使用getChildFragmentManager而不是getFragmentManager