34

FragmentStatePagerAdapter IllegalStateException: <MyFragment> is not currently in the FragmentManagerの複製のように聞こえます が、彼の解決策は私の場合には関係ありません。

めったに次のクラッシュが発生しません。

java.lang.RuntimeException: アクティビティ {MyActivity} を一時停止できません:

...

原因: java.lang.IllegalStateException: Fragment MyFragment {40648258 id=0x7f070051} は現在、android.support.v4.app.FragmentManagerImpl.putFragment(MT:516) の FragmentManager にありません android.support.v4.app.FragmentStatePagerAdapter android.support.v4.view.ViewPager.onSaveInstanceState(MT:881) の .saveState(MT:185)

...

android.view.View.saveHierarchyState(View.java:6238) で com.android.internal.policy.impl.PhoneWindow.saveHierarchyState(PhoneWindow.java:1522) で android.app.Activity.onSaveInstanceState(Activity.java:1138) ) android.support.v4.app.FragmentActivity.onSaveInstanceState(MT:480) で MyActivity.onSaveInstanceState(MT:336)

これは私が理解できない奇妙なコードのようですFragmentStatePagerAdapter:

for (int i=0; i<mFragments.size(); i++) {
    Fragment f = mFragments.get(i);
    if (f != null) {
        if (state == null) {
            state = new Bundle();
        }
        String key = "f" + i;
        mFragmentManager.putFragment(state, key, f);
    }
}

アダプタは myFragmentから取得しているようですmFragmentsが、その状態を に追加できませんFragmentManager

テストデバイスでこれを再現する方法を見つけることができませんでした.一部のユーザーからのみこれを受け取りました.

サポート パッケージ v4 を使用しています。

何か助けはありますか?ありがとう。

4

12 に答える 12

16

これFragmentStatePagerAdapterは、Google が認めているかどうかにかかわらず、バグだらけの恐ろしいコードなので、このコードを使用してこの特定のクラッシュを修正します。

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        // Yet another bug in FragmentStatePagerAdapter that destroyItem is called on fragment that hasnt been added. Need to catch
        try {
            super.destroyItem(container, position, object);
        } catch (IllegalStateException ex) {
            ex.printStackTrace();
        }
    }
于 2015-04-16T16:19:39.377 に答える
10

これは、FragmentStatePagerAdapter が ViewPager に設定され、Fragments が取り込まれているが、ViewPager のレイアウトが発生する前にアクティビティが一時停止しているため、FragmentManager にまだ追加されていない場合に発生する可能性があります。これは、アダプタも onCreate に設定された状態で、onCreate から別のアクティビティを開始することで確実にヒットします。そのような状況では、Adapter の設定を延期し、代わりに onActivityResult を設定することをお勧めします。この問題を参照してください: https://code.google.com/p/android/issues/detail?id=77285

状態を保存する前に、フラグメントが追加されていることを確認するパッチも提出しました。

于 2014-10-13T15:03:31.593 に答える
7

私は正確な例外に遭遇しました。

私の場合、FragmentPagerStateAdapter によって管理されるフラグメントがいくつかありますが、フラグメントの位置が入れ替わることがあります。

getItemPosition() をオーバーライドして新しい位置を返し、notifyDataSetChanged() を呼び出して ViewPager を更新します。すべて正常に動作しますが、ViewPager を離れるとクラッシュが発生することがあります。

数時間掘り下げた後、FragmentPagerStateAdapter にバグがあることがわかりました。

アダプターは状態をキャッシュするだけでなく、「アクティブ」と見なされるフラグメントもキャッシュします

private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();

ただし、フラグメントの位置が無効化または移動されたかどうかはチェックしません。

それがこの例外を取得する方法です:

1. ViewPager と Adapter に A、B、C の 3 つのフラグメントがあります。

2.アダプターで位置を B、A、C に切り替えて、notifyDataSetChanged() を呼び出しました。

3.ViewPager はフラグメントを新しい順序で再レイアウトします。しかし、mFragments キャッシュはまだ {A,B,C} です

4.いくつかのページをスワイプすると、ViewPager はアダプタに最初の Fragment を破棄するように要求します。次に、A ではなくフラグメント B がキャッシュ内で null に設定されます。現在、mFragments は {null,A,C} です。

5.ViewPager を離れると、onSaveInstanceState がトリガーされます。mFragments 内のすべてのフラグメントはアクティブと見なされ、FragmentManagerImpl が A not を検出して例外をスローするまで putFragment() が呼び出されます。

だからここに私のそれほど穏やかではない解決策があります:

1. FragmentPagerStateAdapter ソース コード全体をコピーします。

2. notifyDataSetChanged() メソッドをオーバーライドして、以下のようにキャッシュを再配置します。

@Override
public void notifyDataSetChanged() {
  List<Fragment> oldFragments = new ArrayList<>(mFragments);
  List<Fragment.SavedState> oldStates = new ArrayList<>(mSavedState);
  for (int i = 0; i < getCount(); i++) {
    if (i < mFragments.size()) {
      Fragment f = mFragments.get(i);
      if (f != null) {
        int newPosition = getItemPosition(f);
        if (newPosition == POSITION_UNCHANGED || newPosition == i) {
        } else if (newPosition == POSITION_NONE) {
          if (i < mSavedState.size()) {
            mSavedState.set(i, null);
          }
          mFragments.set(i, null);
        } else {
          while (i >= mFragments.size()) {
            mFragments.add(null);
          }
          if (oldStates.size() > i) {
            mSavedState.set(newPosition, oldStates.get(i));
          }
          mFragments.set(newPosition, oldFragments.get(i));
        }
      } else {
        /*
         * No Fragment but that's possible there's savedState and position has
         * changed.
         */
      }
    }
  }
  super.notifyDataSetChanged();
}

それがあなたの何人かのために働くことを願っています!

于 2014-09-05T05:47:29.823 に答える
7

フラグメント階層がある場合getChildFragmentManager()の代わりに使用します。getFragmentManager()例えば。フラグメントページャーがある場合。

于 2013-10-12T09:21:47.997 に答える
1

独自のコードからFragmentStatePagerAdapter.instantiateItem()を呼び出していますか? 一般に、ViewPager はこのメソッドを呼び出す唯一のクライアントである必要がありますが、このメソッドに依存する他の制限の回避策を見つけるのは簡単です。

動作の仕方からFragmentStatePagerAdapter、アダプターはフラグメントをインスタンス化し、それをフラグメントの内部コレクションに追加し、そのフラグメントを FragmentManager に追加するトランザクションを開始したと推測しますが、そのフラグメントトランザクションはコミットまたは実行されていません。これはinstantiateItem()、要求された Fragment がまだインスタンス化されていない場合に行うこととまったく同じです。

別のメソッドFragmentStatePagerAdapter.finishUpdate()は、保留中のトランザクションの実行だけでなく、トランザクションのコミットも担当します。 finishUpdate() は、instantiateItem() の後に呼び出す必要があります。そうしないと、Fragment が FragmentManager に追加されない場合があります。

次のようなことを試してください:

// Get the current Fragment presented by the ViewPager.
pagerAdapter.startUpdate(viewPager);
Fragment fragment = pagerAdapter.instantiateItem(viewPager, viewPager.getCurrentItem());
pagerAdapter.finishUpdate(viewPager);
return fragment;

startUpdate() には、API レベル 19 の時点で空の実装があります。

于 2013-11-26T06:56:55.100 に答える
0

使ってみて

use fragmentTransaction.add()
于 2013-11-14T23:54:12.580 に答える
0

onSaveInstanceStateおよびをアクティビティに実装したかどうかを再onRestoreInstanceState確認し、フラグメントの状態を正しく保存およびロードしていることを確認します。

于 2016-12-07T23:05:55.190 に答える
0

ViewPager のフラグメントが修正されました。アダプターのフラグメントを置き換えるのではなく、フラグメントの別のセットを指定して notifyDataSet を変更するか、FrameLayout を利用して、ビュー ページャー タブの現在のフラグメントの上に別のフラグメントを表示します。

動作する私のソリューションがあります:

デフォルトのスワイプが無効になっている ViewPager とともにフラグメント レベルで適用されるスワイプ ジェスチャ

于 2013-11-20T12:46:22.520 に答える
0

あなたは使用してみることができますmFragmentManager.add();

于 2013-07-15T21:12:48.543 に答える