32

フラグメントを保持するこのアクティビティがあります。このフラグメント レイアウトは、いくつかのフラグメント (実際には 2 つ) を持つビュー ページャーで構成されます。

ビューページャーが作成されると、そのアダプターが作成され、getItem呼び出されてサブフラグメントが作成されます。偉大な。

画面を回転すると、フレームワークがフラグメントの再作成を処理し、アダプタがonCreateメイン フラグメントから再度作成されますgetItemが、呼び出されないため、アダプタは 2 つのフラグメントではなく間違った参照 (実際には null) を保持します。

私が見つけたのは、フラグメント マネージャー (つまり、子フラグメント マネージャー) に というフラグメントの配列が含まれていることmActiveです。もちろん、コードからアクセスすることはできません。ただし、次のgetFragment方法があります。

@Override
public Fragment getFragment(Bundle bundle, String key) {
    int index = bundle.getInt(key, -1);
    if (index == -1) {
        return null;
    }
    if (index >= mActive.size()) {
        throwException(new IllegalStateException("Fragement no longer exists for key "
                + key + ": index " + index));
    }
    Fragment f = mActive.get(index);
    if (f == null) {
        throwException(new IllegalStateException("Fragement no longer exists for key "
                + key + ": index " + index));
    }
    return f;
}

タイプミスについてはコメントしません:)
これは、アダプターコンストラクターでフラグメントへの参照を更新するために実装したハックです。

// fm holds a reference to a FragmentManager
Bundle hack = new Bundle();
try {
    for (int i = 0; i < mFragments.length; i++) {
        hack.putInt("hack", i);
        mFragments[i] = fm.getFragment(hack, "hack");
    }
} catch (Exception e) {
    // No need to fail here, likely because it's the first creation and mActive is empty
}

私は誇りに思っていません。これは機能しますが、醜いです。画面の回転後に有効なアダプターを使用する実際の方法は何ですか?

PS:ここに完全なコードがあります

4

6 に答える 6

0

問題は、getItem()inFragmentPageAdapterの名前が間違っていることです。と名付けるべきcreateItem()でした。それが機能する方法getItem()はフラグメントを作成するためのものであり、フラグメントをクエリ/検索するために呼び出すのは安全ではないためです。

私の推奨事項は、現在の FragmentPagerAdapter のコピーを作成し、そのように変更することです。

追加:

    public abstract Fragment createFragment(int position);

getItem を次のように変更します。

public Fragment getItem(int position) {
    if(containerId!=null) {
        final long itemId = getItemId(position);
        String name = makeFragmentName(containerId, itemId);
        return mFragmentManager.findFragmentByTag(name);
    } else {
        return null;
    }
}

最後にそれをinstantiateItemに追加します:

    if(containerId==null)
        containerId = container.getId();
    else if(containerId!=container.getId())
        throw new RuntimeException("Container id not expected to change");

この要点で完全なコード

この実装は、より安全で使いやすく、Google エンジニアの元のアダプターと同じパフォーマンスを備えていると思います。

于 2016-10-18T11:07:43.020 に答える