web-dev-qa-db-ja.com

フラグメント内のフラグメント

これが実際にAndroid AP​​Iのバグかどうか疑問に思っています。

私のようなセットアップがあります:

┌----┬---------┐
|    |         |
|  1 |    2    |
|    |┌-------┐|
|    ||       ||
|    ||   3   ||
└----┴┴-------┴┘
  1. 右側のペインにフラグメント#2(検索画面)をロードするメニューです。
  2. 結果リストであるフラグメント#3を含む検索画面です。
  3. 結果リストはいくつかの場所で使用されます(それ自体で機能する高レベルのフラグメントとして含む)。

この機能は電話で完璧に機能します(1と2と3はActivityFragmentsです)。

ただし、このコードを使用した場合:

    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();       
    Fragment frag = new FragmentNumber2();
    if(toLoad != null) frag.setArguments(toLoad);
    transaction.replace(R.id.rightPane, frag);      
    transaction.commit();

R.id.leftPaneR.id.rightPaneは、水平線形レイアウトの<fragment>sです。

上記のコードは、常駐するフラグメントを削除し、それを新しいフラグメントで置き換えることを理解しています。すばらしい...このコードが2回目に実行されると、次の例外が発生するため、明らかにそれは起こりません。

07-27 15:22:55.940: ERROR/AndroidRuntime(8105): Caused by: Java.lang.IllegalArgumentException: Binary XML file line #57: Duplicate id 0x7f080024, tag null, or parent id 0x0 with another fragment for FragmentNumber3

これは、FragmentNumber3のコンテナが複製され、一意のIDがなくなったために発生します。新しいフラグメントが追加される前に、最初のフラグメントは破壊されていません(?)(私の考えでは、それはreplacedではないことを意味します)。

誰かがこれが可能かどうかを教えてもらえますか( この答え はそうではないことを示唆しています)、またはバグですか?

145
Graeme

ネストされたフラグメントは現在サポートされていません。フラグメントを別のフラグメントのUI内に配置しようとすると、未定義の動作が壊れる可能性があります。

Update:ネストされたフラグメントがサポートされていますAndroid以降_ 4.2(およびAndroid Support Library rev 11): http://developer.Android.com/about/versions/Android-4.2.html#NestedFragments

NOTEthis docs )に従って: "注:レイアウトを膨らませることはできませんそのレイアウトに<fragment>が含まれる場合、フラグメントにネストされます。ネストされたフラグメントは、フラグメントに動的に追加された場合にのみサポートされます。 "

202
hackbod

ネストされたフラグメントは、Android 4.2以降でサポートされています

AndroidSupport Libraryは、ネストされたフラグメントもサポートするようになりました、ネストされたフラグメントデザインをAndroid 1.6以降に実装できます。

フラグメントをネストするには、フラグメントを追加するフラグメントでgetChildFragmentManager()を呼び出すだけです。これは、フラグメントトランザクションを作成するためにトップレベルアクティビティから通常行うように使用できるFragmentManagerを返します。たとえば、次のコードは、既存のFragmentクラス内からフラグメントを追加します。

Fragment videoFragment = new VideoPlayerFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.video_fragment, videoFragment).commit();

ネストされたフラグメントの詳細については、これらのチュートリアルをご覧ください
パート1
パート2
パート

そして、これは ネストされたフラグメントのベストプラクティス について議論するSO投稿です。

97
Raneez Ahmed

..親フラグメントのdestroyviewメソッドでネストされたフラグメントをクリーンアップできます。

@Override
    public void onDestroyView() {

      try{
        FragmentTransaction transaction = getSupportFragmentManager()
                .beginTransaction();

        transaction.remove(nestedFragment);

        transaction.commit();
      }catch(Exception e){
      }

        super.onDestroyView();
    }
33
furykid

私が開発しているアプリケーションは、フラグメントを起動するアクションバーのタブと同様にレイアウトされています。これらのフラグメントの一部には、複数のフラグメントが埋め込まれています。

アプリケーションを実行しようとしたときに同じエラーが発生していました。タブの選択を解除してから再選択した後にxmlレイアウト内でフラグメントをインスタンス化すると、インフレータエラーが発生するようです。

これを解決して、xmlのすべてのフラグメントをLinearlayoutsに置き換え、フラグメントマネージャ/フラグメントトランザクションを使用してフラグメントをインスタンス化し、すべてが少なくとも現在テストレベルで正しく動作しているようです。

これがお役に立てば幸いです。

14
draksia

私は同じ問題に直面しており、数日間苦労しており、タブを選択/選択解除したときにfragment.hide()/ fragment.show()を使用することが最も簡単な解決策であると言うべきです()。

public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft)
{
    if (mFragment != null)
        ft.hide(mFragment);
}

画面の回転が発生すると、すべての親および子フラグメントが正しく破棄されます。

このアプローチにはもう1つの利点もあります。hide()/ show()を使用してもフラグメントビューの状態が失われないため、たとえばScrollViewsの以前のスクロール位置を復元する必要はありません。

問題は、フラグメントが見えないときにデタッチしないことが正しいかどうかわからないことです。 TabListenerの公式例は、フラグメントは再利用可能であり、メモリで汚染しないように念頭に置いて設計されていると思いますが、少数のタブしかなく、ユーザーが頻繁にそれらを切り替える場合があると思いますそれらを現在のアクティビティに添付したままにするのが適切です。

より経験豊富な開発者からコメントを聞きたいです。

4
ievgen

ネストされたフラグメントが削除または複製されていないことがわかった場合(アクティビティの再起動時、画面の回転時など)、変更してみてください:

transaction.add(R.id.placeholder, newFragment);

transaction.replace(R.id.placeholder, newFragment);

上記で解決しない場合は、次を試してください:

Fragment f = getChildFragmentManager().findFragmentById(R.id.placeholder);

FragmentTransaction transaction = getChildFragmentManager().beginTransaction();

if (f == null) {
    Log.d(TAG, "onCreateView: fragment doesn't exist");
    newFragment= new MyFragmentType();
    transaction.add(R.id.placeholder, newFragment);
} else {
    Log.d(TAG, "onCreateView: fragment already exists");
    transaction.replace(R.id.placeholder, f);
}
transaction.commit();

学んだ ここ

0
Voy