web-dev-qa-db-ja.com

フラグメント内にフラグメントビューページャーを表示する

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);
    }
}
_
54
howettl

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);
        }
}
60
Yashwanth Kumar

FragmentStatePagerAdapterの代わりにFragmentPageAdapterを使用できます。フラグメントが削除されます。

38
Leszek

私はちょうどこの同じ問題に出くわしました。 FragmentViewPagerをホストする必要があるFragmentsがありました。 Fragmentの上に別のViewPagerFragmentを積み重ねてから、それを押し返すと、IllegalStateExceptionが返されます。ログを確認した後(新しいFragmentをスタックするとき)、ViewPagerFragmentがライフサイクルメソッドを通過して停止および破棄しますが、その子FragmentsViewPageronResumeにとどまります。 FragmentsFragmentManagerではなく、ViewPagerFragmentFragmentManagerによって子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;
}
25
Steven Byle

Handler.post()を使用して、元のフラグメントトランザクションの外部でアダプターを設定しました。

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

ViewCreatedのTabIndicatorでviewPagerアダプターを初期化しようとしたときに、この問題に直面しました。それについてオンラインで読んだ後、これはフラグメントがまだアクティビティに追加されていないためであることがわかった。そのため、初期化コードをフラグメントのonStart()に移動しました。これで問題が解決するはずです。しかし、私にとっては同じ問題が再び発生していました。

しかし、それは私のコードで、すべてがうまく機能したことをブロックした後、executePendingTransactions()を明示的に呼び出すことによって保留中のタスクの通常の非同期実行をバイパスしようとしたためです

0
Sanket

ドキュメントによると: https://developer.Android.com/reference/Android/app/Fragment.html#getChildFragmentManager()

ネスティングフラグメントを管理する場合は、getChildFragmentManagerの代わりにgetFragmentManagerを使用する必要があります。

0

親フラグメントをロードすると、メッセージ「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ソースを参照してください。

https://github.com/Android/platform_frameworks_support/blob/master/v4/Java/Android/support/v4/app/FragmentManager.Java#L9

または、こちらのページをご覧ください。元々のアイデアは彼女からであり、実際は私ではありません。 http://y-anz-m.blogspot.jp/2012/04/androidfragment-viewpager-id.html

0
Kugyo

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());
0
Karan

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);
0
Slickelito