55

ViewPagerを含むフラグメントがあります。ViewPagerは、フラグメントのセットを含むアダプターに関連付けられています。

親フラグメントをロードするIllegalStateExceptionと、次のメッセージが表示されますjava.lang.IllegalStateException: Recursive entry to executePendingTransactions

いくつかの調査により、システムは別のフラグメント内のフラグメントを表示できないという結論に達しましたが、ViewPagerを使用してこれを正確に行うことができるという兆候があるようです(他のフラグメントで使用するViewPagerのバグ)。

実際、mPager.setAdapter(mAdapter)押されたときにViewPagerを呼び出すボタンを親フラグメントに追加すると、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);
    }
}
4

9 に答える 9

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);
        }
}
于 2011-10-08T22:56:51.977 に答える
39

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

于 2012-01-31T14:17:21.647 に答える
26

私はちょうどこれと同じ問題に遭遇しました。のをFragmentホストするために必要なものがViewPagerありましたFragmentsFragmentの上に別の物を積み上げてViewPagerFragmentから反撃すると、が表示されますIllegalStateException。ログを確認した後(新しいをスタックする場合)、ライフサイクルメソッドを実行して停止および破棄することがFragmentわかりましたが、の子はにとどまります。私は、子供たちがのではなく、のによって管理されるべきであることに気づきました。ViewPagerFragmentFragmentsViewPageronResumeFragmentsFragmentManagerViewPagerFragmentFragmentManagerActivity

当時、上記の答えは、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;
}
于 2013-01-24T15:57:35.633 に答える
19

Handler.post()は元のフラグメントトランザクションの外にアダプタを設定するために使用しました:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            mViewPager.setAdapter(mAdapter);     
        }
    });        
}
于 2012-04-27T22:50:53.630 に答える
0

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

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

于 2013-04-03T22:47:18.233 に答える
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;
    }

マジックナンバー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#L900

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

于 2013-07-08T12:41:19.250 に答える
0

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);
于 2013-08-14T14:10:35.767 に答える
0

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

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

于 2017-03-15T16:07:21.770 に答える
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());
于 2018-11-30T05:33:25.790 に答える