web-dev-qa-db-ja.com

Android Honeycomb:FrameLayoutのフラグメントを再作成せずに変更するにはどうすればよいですか?

フラグメントを常に再作成せずに切り替えることは可能ですか?もしそうなら、どのように?

ドキュメント内 フラグメントを置き換える方法の例を見つけました。

_// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);

// Commit the transaction
transaction.commit();
_

ただし、フラグメントが必要になるたびに、フラグメントを最初から作成する必要はありません。

私はまた この例 フラグメントの非表示/表示を見つけました:

_// The content view embeds two fragments; now retrieve them and attach
// their "hide" button.
FragmentManager fm = getFragmentManager();
addShowHideListener(R.id.frag1hide, fm.findFragmentById(R.id.fragment1));
addShowHideListener(R.id.frag2hide, fm.findFragmentById(R.id.fragment2));
_

しかし、XMLファイルの外部にIDを持つフラグメントを作成するにはどうすればよいですか?

これは この質問 に関連していると思いますが、答えはありません。 :/

よろしくお願いします、クラゲ

編集:

それが私が今それをしている方法です:

_Fragment shown = fragmentManager.findFragmentByTag(shownFragment);

//...

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (shown != null) fragmentTransaction.hide(shown);

//switch statetement for menu selection, just one example:

SettingsFragment set = (SettingsFragment) fragmentManager.findFragmentByTag(SET);
Toast.makeText(this, "Settings:" + set, Toast.LENGTH_LONG).show();
if (set == null)
{
        set = new SettingsFragment();
        fragmentTransaction.add(R.id.framelayout_content, set, SET);
}
else fragmentTransaction.show(set);
shownFragment = SET;
fragmentTransaction.commit();
_

設定を呼び出してから別の何かを呼び出してから設定に戻ると、トーストは最初に「null」を表示し、次に「Settings:SettingsFragment {40ef ...」を表示します。

ただし、fragmentTransaction.add(R.id.framelayout_content, set, SET);fragmentTransaction.replace(R.id.framelayout_content, set, SET);に置き換えると、「null」、「null」、「null」が表示され続けるため、タグでフラグメントが見つからないようです。

Edit2:

fragmentTransaction.addToBackStack(null);を追加することでうまくいきました。 :)これにより、どのフラグメントが表示されているかを非表示/記憶する全体が保存されるので、これが最もエレガントなソリューションだと思います。

this チュートリアルがこのトピックで非常に役立つことがわかりました。

Edit3:

私のコードを見て、私はいくつかの部分を取り除くことができることに気づいたので、それを次のように変更しました:

_FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (shown != null) fragmentTransaction.hide(shown);
Settings set = (Settings) fragmentManager.findFragmentByTag(SET);
if (set == null) set = new Settings();

fragmentTransaction.replace(R.id.framelayout_content, set, SET);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
_

ただし、これは_IllegalStateException: Fragment already added_を呼び出しました。これは、 ここ とほとんど同じです。これを防ぐ簡単な方法はありますか?そうでなければ、私は非表示/表示ビットに戻るかもしれないと思います。

14
jellyfish

再作成を避けようとしているものによって異なります。

_// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
_

例の例では、newFragmentから戻るボタンを押すと、前のフラグメントが表示され(onCreateView、onActivityCreatedは表示されますが、onCreateは表示されません)、フラグメントがそのように再作成されないようにします。 newFragmentについては、onCreateやonActivityCreatedなどで必要に応じて内部状態を更新するために再度使用する場合は、引き続き使用できます。

編集:

右側のペインで各エントリが異なるフラグメントを呼び出すメニューリストがある場合、バックスタックに追加することは望ましくありません。このためには、各フラグメントでadd(...)を事前に呼び出して、必要に応じて各フラグメントを非表示/表示するだけで済みます(これはテストしていません)。それ以外の場合は、各フラグメントへの参照を保持することをお勧めします。別のメニュー項目を選択するときにreplace(...)を呼び出して、バックスタックに追加しないようにします。

5
PJL

回避するには

IllegalStateException:フラグメントはすでに追加されています

正常に機能している回避策を見つけました。トランザクションでは、remove(AFrag)の代わりにadd(BFrag)replace()を使用してください。

バグのようです: 受け入れられた回答の4番目のコメント

4
Axel M. Garcia
fragmentTransactionOnClick.setTransition(FragmentTransaction.TRANSIT_EXIT_MASK);

.setTransition.exit transit_exit_maskを追加すると、前のビューは表示されません

1
anil

「タグ」機能を使用する方法を見つけました。

_//...
fragmentTransaction.add(R.id.framelayout_content, fragment1, "foo");
fragmentTransaction.add(R.id.framelayout_content, fragment2, "bar");

//...

fragmentManager.findFragmentByTag("foo");
fragmentManager.findFragmentByTag("bar");
_

ただし、これは少し非同期的に機能するようです。 findFragmentByTagの直後にcommitを呼び出すと、nullが返されます。その後、私の場合はOnOptionsItemSelectedイベントで、フラグメントが見つかりました。

findFragmentById(int)という関数もありますが、あまり役に立ちません。 Id(XMLレイアウトで指定されていない場合)はコンテナーのIDと同じであるため、この場合は_R.id.framelayout_content_です。後でこのIDを使用して関数を呼び出すと、添付されているフラグメントの1つにのみアクセスできます。 (これが最後だと思いますが、チェックしていません。でも、いつも同じようです。)

FrameLayoutから「アクティブな」フラグメントを取得する方法を一目見ただけでは見つけられなかったので、最後に表示されたフラグメントのタグをどこかに保存するつもりだと思います。

0
jellyfish