我有一个包含ViewPager的片段。 ViewPager与包含一组片段的适配器相关联。
加载父片段后,我遇到一条IllegalStateException
,其中包含以下消息:java.lang.IllegalStateException: Recursive entry to executePendingTransactions
。
一些研究使我得出的结论是系统无法在另一个片段中显示片段,但是似乎有一些迹象表明可以通过使用ViewPager(A bug in ViewPager using it with other fragment)完成此操作。
事实上,如果我在按下时在我的ViewPager上调用mPager.setAdapter(mAdapter)
的父片段添加一个按钮,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);
}
}
答案 0 :(得分:60)
使用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);
}
}
答案 1 :(得分:37)
您可以使用FragmentStatePagerAdapter
代替FragmentPageAdapter
。它会为你删除碎片。
答案 2 :(得分:24)
我刚遇到同样的问题。我有一个Fragment
需要托管ViewPager
Fragments
。当我在Fragment
之上堆叠另一个ViewPagerFragment
,然后回击时,我会得到一个IllegalStateException
。检查完日志后(堆叠新的Fragment
时),我发现我的ViewPagerFragment
将通过其生命周期方法停止并销毁,但Fragments
中的子ViewPager
将留在onResume
。我意识到,Fragments
应该为FragmentManager
管理ViewPagerFragment
,而不是FragmentManager
的{{1}}。
我当时理解,上述答案是为了解决Activity
无法生育孩子Fragments
的限制。但是,现在最新的支持库支持Fragments
嵌套,您不再需要为Fragment
设置适配器,并且只需要传递ViewPager
即可。到目前为止,这对我来说非常合适。
getChildFragmentManager()
答案 3 :(得分:19)
我使用Handler.post()
在原始片段事务之外设置适配器:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mHandler.post(new Runnable() {
@Override
public void run() {
mViewPager.setAdapter(mAdapter);
}
});
}
答案 4 :(得分:0)
尝试在ViewCreated上的TabIndicator上初始化viewPager适配器时,我遇到了这个问题。在网上阅读之后,我意识到这可能只是因为片段尚未添加到活动中。所以我将初始化代码移动到片段的onStart(),这应该可以解决你的问题。但不适合我,我仍然会再次遇到同样的问题。
但那是因为在我的代码中,我试图通过显式调用executePendingTransactions()来阻止正常的异步执行挂起任务,阻塞后一切运行良好
答案 5 :(得分:0)
加载父片段后,遇到IllegalStateException并带有消息:java.lang.IllegalStateException:executePendingTransactions的递归入口。
一些研究使我得出结论,系统无法在另一个片段中显示片段,但是似乎有一些迹象表明可以通过使用ViewPager完成此操作(ViewPager中的一个错误与其他片段一起使用) )。
显式设置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
答案 6 :(得分:0)
使用Thomas Amssler撰写的这篇精彩文章:http://tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part-ii.html
我创建了一个可用于创建所有类型片段的适配器。 适配器本身如下所示:
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);
答案 7 :(得分:0)
根据文件:https://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager()
如果您想管理嵌套片段,则必须使用getChildFragmentManager
代替getFragmentManager
。
答案 8 :(得分:0)
代替在AsyncTask或任何处理程序中设置适配器,只需在 onResume()部分中编写该部分代码
这样做,您将:
onResume()的代码如下:
@Override
public void onResume() {
super.onResume();
if(mViewPager.getAdapter()==null||mViewPager.getAdapter().getCount()==0)
mViewPager.setAdapter(mAdapter);
}
也在 onCreateView 中 代替
mAdapter = new ViewPagerAdapter(getFragmentManager());
替换为
mAdapter = new ViewPagerAdapter(getChildFragmentManager());