‘google maps’ タグのついている投稿

FragmentTabHost+SupportMapFragmentで画面が真っ白になる

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を実行しておけば、地図が二重に表示されるなどの現象はなくなります。