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


145

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

私はそのような設定をしています:

┌----┬---------┐
|    |         |
|  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>

上記のコードが常駐しているフラグメントを削除し、それを新しいフラグメントに置き換えることは私の理解です。このコードが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がなくなったために発生します。最初のFragmentは、新しいFragmentが追加される前に破棄されていません(?)(私の考えでは、置き換えられていません)。

これが可能であるか(この答えは不可能であることが示唆されます)、それはバグですか?



6
@rdsこれは古代の質問です。重複としてマークするのは少し無意味です。
pietv8x 2015

回答:


203

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

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

NOTE(につきとしてこのドキュメント):「注:あなたはそのレイアウトが含まれてフラグメントにレイアウトを膨らませることはできません<fragment>。動的フラグメントに添加したときにネストされた断片のみがサポートされています。


14
最初の実装の設計目標ではなかったため、サポートされていません。私はこの機能のリクエストをたくさん聞いたので、おそらくいつかは行われるでしょうが、いつものように、優先的にそれと競合する他の多くのものがあります。
ハックボット

4
FragmentActivity、FragmentManager、およびFragmentTransactionを拡張することで、これを管理しました。基本的な前提は、私​​のアクティビティでDeferringFragmentActivityを拡張することであり、同じAPIを提供するため、他のコードは変更されません。getFragmentManagerを呼び出すと、DeferringFragmentManagerというインスタンスが取得され、beginTransactionを呼び出すと、DeferredTransactionが取得されます。このトランザクションは、呼び出されたメソッドと引数とともにPOJOを格納します。commitが呼び出されると、保留中のすべてのDeferredTransactionsが最初に検索されます。すべてのトランザクションがコミットされたら、実際のトランザクションを開始し、格納されているすべてのメソッドを引数で実行します。
dskinner

11
その点は今です。ネストされたFragmentはAndroid APIの一部になりました。developer.android.com/about/versions/…
Alex Lockwood 2012年

9
なんという悪夢:Fragmentで<fragment>を使用していて、そのFragmentが子フラグメントを使用している場合でも、明確なエラーで失敗することはありません(「子フラグメントをレイアウトフラグメントに追加できません」)。 「フラグメントがビューを作成しなかった」などの例外を除いて、不可解に失敗します。デバッグには数時間かかります...
Glenn Maynard

6
@MartínMarconciniは確かですが、APIによって提供される機能に基づいて、それがまったく明らかではありません。許可されていないものがある場合は、明確に文書化する必要があります。期待どおりに機能していないために、開発者に髪の毛を抜いてもらう必要はありません。
dcow 2013

98

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

Android Support 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
パート3を実行してください。

ネストされたフラグメントのベストプラクティスについて説明するSOの投稿です。


Nestedfragmentの主な欠点は、childmenuからoptionmenuを呼び出せないことです:(ABSを使用している場合!
LOG_TAG

私の問題を調べてもらえますか?その非常に似ています..stackoverflow.com/questions/32240138/ … 。私にとって、子供フラネットはコードから膨らんでいません
Nicks

33

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

@Override
    public void onDestroyView() {

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

        transaction.remove(nestedFragment);

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

        super.onDestroyView();
    }

4
SetAlwaysFinish(bricolsoftconsulting.com/2011/12/23/…)を使用してライフサイクルテストを行うと、常に完了が有効な状態で別のアクティビティが実行されると、このコードによってエラーが発生することがわかります(IllegalStateException:このアクションを実行できません) onSaveInstanceStateの後)。上記のコードをtry / catchでラップすることは、最も洗練されたソリューションではありませんが、すべてが機能するようです。
Theo

これはほとんど機能しました。後で、UIの描画でStackoverflowを取得しました。ネストされたフラグメントを完全に回避する...
neteinstein

14

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

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

私はこれを解決して、xml内のすべてのフラグメントをLinearlayoutsに置き換え、次にフラグメントマネージャー/フラグメントトランザクションを使用してフラグメントをインスタンス化し、少なくとも現時点ではすべてが正しく機能しているように見えます。

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


誰もがこのアプローチの有効性についてコメントできますか?Fragmentsを1レベルだけ使用できるのは残念ですが、その場合はまったく使用しないこともあります。それらをプレースホルダービューグループにプログラムで追加しても、警告なしに機能しますか?
ラファエルノブレ、2012年

まだ私のために働いているようですが、私はそれらをビューホルダーに入れたり出したりしても問題ありません。1つの注意点は、これをハニカムでのみ行っているので、アイスクリームサンドイッチとの互換性はありません。
ドラクシア

4

私は同じ問題に直面し、それと2日間苦労しており、これを克服する最も簡単な方法は、タブが選択されている/選択されていないときにfragment.hide()/ fragment.show()を使用することだと思います()。

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

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

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

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

より経験豊富な開発者からのコメントをお願いします。


0

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

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

ここで学んだ

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.