148

これが実際に 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 は、新しいものが追加される前に破棄されていません (?) (つまり、置き換えられていないということです)。

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

4

6 に答える 6

204

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

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

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

于 2011-07-27T16:17:37.010 に答える
98

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

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

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

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

ネストされたフラグメントについての理解を深めるには、次のチュートリアルを参照してください。
パート 1
パート 2
パート 3

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

于 2012-06-13T17:51:14.487 に答える
34

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

@Override
    public void onDestroyView() {

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

        transaction.remove(nestedFragment);

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

        super.onDestroyView();
    }
于 2011-10-31T12:37:13.917 に答える
14

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

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

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

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

于 2011-10-26T15:34:53.103 に答える
4

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

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

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

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

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

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

于 2012-07-19T11:28:23.727 に答える
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();

ここで学んだ

于 2016-06-19T14:10:27.837 に答える