ViewPagerを含むフラグメントがあります。 ViewPagerは、フラグメントのセットを含むアダプターに関連付けられています。
親フラグメントを読み込むと、_Java.lang.IllegalStateException: Recursive entry to executePendingTransactions
_というメッセージが表示されたIllegalStateException
が表示されます。
いくつかの研究により、システムは別のフラグメント内にフラグメントを表示できないという結論に至りましたが、ViewPagerを使用してこれを正確に行うことができるという兆候があるようです( ViewPagerのバグ他のフラグメントと一緒に )。
実際、押されたときに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);
}
}
_
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);
}
}
FragmentStatePagerAdapter
の代わりにFragmentPageAdapter
を使用できます。フラグメントが削除されます。
私はちょうどこの同じ問題に出くわしました。 Fragment
のViewPager
をホストする必要があるFragments
がありました。 Fragment
の上に別のViewPagerFragment
を積み重ねてから、それを押し返すと、IllegalStateException
が返されます。ログを確認した後(新しいFragment
をスタックするとき)、ViewPagerFragment
がライフサイクルメソッドを通過して停止および破棄しますが、その子Fragments
はViewPager
はonResume
にとどまります。 Fragments
のFragmentManager
ではなく、ViewPagerFragment
のFragmentManager
によって子Activity
を管理する必要があることに気付きました。
当時、上記の答えは、Fragments
が子を持つことができないという制限を回避することでした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);
}
});
}
ViewCreatedのTabIndicatorでviewPagerアダプターを初期化しようとしたときに、この問題に直面しました。それについてオンラインで読んだ後、これはフラグメントがまだアクティビティに追加されていないためであることがわかった。そのため、初期化コードをフラグメントのonStart()に移動しました。これで問題が解決するはずです。しかし、私にとっては同じ問題が再び発生していました。
しかし、それは私のコードで、すべてがうまく機能したことをブロックした後、executePendingTransactions()を明示的に呼び出すことによって保留中のタスクの通常の非同期実行をバイパスしようとしたためです
ドキュメントによると: https://developer.Android.com/reference/Android/app/Fragment.html#getChildFragmentManager()
ネスティングフラグメントを管理する場合は、getChildFragmentManager
の代わりにgetFragmentManager
を使用する必要があります。
親フラグメントをロードすると、メッセージ「Java.lang.IllegalStateException:executePendingTransactionsへの再帰的エントリ」でIllegalStateExceptionが発生します。
一部の研究により、システムが別のフラグメント内のフラグメントを表示できないという結論に至りましたが、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;
}
マジックリソース100の代わりに、xmlリソースでidを使用できます。
<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
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());
Thomas Amsslerによるこの素晴らしい投稿の使用: 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);