在片段中显示片段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
应该由ViewPagerFragment
的FragmentManager
pipe理,而不是Activity
的FragmentManager
。
当时我明白了,上面的答案是为了解决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源文件。
或者看到这个页面(日文)。 原来的想法是从她,实际上,不是我。 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
。