Android Support Library v4を使っていますが、FragmentTabHostのタブのひとつにSupportMapFragmentを継承したFragmentを配置、その地図上のマーカーから同じタブ内に詳細情報表示用のFragmentを表示させるようにしていました。
詳細情報表示用のFragmentを開いたまま、他のタブに行く際に、Fragmentスタックを全部クリアしてから移動するのですが、そうするとこのタブに戻ってきたときにSupportMapFragmentがまったく反応しなくなってしまいます。
対策としては、一度detach/removeしておいて、再度SupportMapFragmentのインスタンス化をして、Transactionにaddという流れでした。
@Override public void onTabChanged(String tabId) { FragmentManager fm = getSupportFragmentManager(); // 移動前に既存のFragmentスタックをクリアする for (int i = 0; i < fm.getBackStackEntryCount(); ++i) { fm.popBackStack(); } // 地図タブから移動する場合は、再アクティブ化のために一度Fragmentをデタッチする if (lastTabId != null && lastTabId.equals("map_section")) { MapSectionFragment fragment = (MapSectionFragment) fm .findFragmentByTag(lastTabId); if (fragment != null) { FragmentTransaction ft = fm.beginTransaction(); ft.detach(fragment); ft.remove(fragment); ft.commit(); } } // 地図タブを開くときは、removeされていれば再インスタンス化する if (tabId.equals("map_section")) { // FragmentTabHost.onTabChangedでcommitされたスタックを先に反映させないとfindできない fm.executePendingTransactions(); MapSectionFragment fragment = (MapSectionFragment) fm .findFragmentByTag(tabId); FragmentTransaction ft = fm.beginTransaction(); if (fragment == null) { // インスタンス化 fragment = (MapSectionFragment) Fragment.instantiate(this, MapSectionFragment.class.getName(), null); // Fragmentを追加 ft.add(R.id.content, fragment, "map_section"); } ft.commit(); } // 最後に開いたタブのタグを保持する lastTabId = tabId; }
今回キモだったのはexecutePendingTransactions()です。
v4/java/android/support/v4/app/FragmentTabHost.java – platform/frameworks/support – Git at Google
FragmentTabHostのソースを見ると、doTabChangedメソッドで同様の処理を実行してFragmentのインスタンス化、追加を実行、コミットしているにも関わらず、findFragmentByTagがnullを返す現象が発生しました。
これはコミットが実際にはすぐには実行されず、メインスレッドにスケジューリングされるためだそうです。
android – Can’t find fragment by tag – Stack Overflow
ドキュメントに書いてありました。
FragmentTransaction | Android Developers
executePendingTransactionsを実行しておけば、地図が二重に表示されるなどの現象はなくなります。
タグ: fragment, google maps