iosched (2)

今、3.x な環境導入ちうなのですが、ADT の導入に時間がかかっております。
で、昨晩出てきた以下な疑問点なんですが

  • FragmentReplaceInfo って何
  • getSupportFragmentManager().popBackStack() メソドが何をしているのか

これから確認入れてみます。

FragmentReplaceInfo

Google 先生は何も知らんとのことなので grep で探してみたら BaseMultiPaneActivity の中で定義されている模様です。
以下。

    /**
     * A class describing information for a fragment-substitution, used when a fragment can act
     * in place of an activity.
     */
    protected class FragmentReplaceInfo {
        private Class mFragmentClass;
        private String mFragmentTag;
        private int mContainerId;

        public FragmentReplaceInfo(Class fragmentClass, String fragmentTag, int containerId) {
            mFragmentClass = fragmentClass;
            mFragmentTag = fragmentTag;
            mContainerId = containerId;
        }

        public Class getFragmentClass() {
            return mFragmentClass;
        }

        public String getFragmentTag() {
            return mFragmentTag;
        }

        public int getContainerId() {
            return mContainerId;
        }
    }

ありゃ、コンストラクタで設定される属性の getter しか無いな。ちなみに onSubstituteFragmentForActivityLaunch メソドの用例を見るに Id な属性は layout な id を渡してるので表示する場所になるのか。

getSupportFragmentManager().popBackStack() メソド

ええとまず、getSupportFragmentManager() メソドを確認。これですが BaseMultiPaneActivity の openActivityOrFragment メソド (ScheduleMultiPaneActivity#onSubstituteFragmentForActivityLaunch メソドの呼び出し元) でも使ってますね。

                final Bundle arguments = intentToFragmentArguments(intent);
                final FragmentManager fm = getSupportFragmentManager();

                try {
                    Fragment fragment = (Fragment) fri.getFragmentClass().newInstance();
                    fragment.setArguments(arguments);

                    FragmentTransaction ft = fm.beginTransaction();
                    ft.replace(fri.getContainerId(), fragment, fri.getFragmentTag());
                    onBeforeCommitReplaceFragment(fm, ft, fragment);
                    ft.commit();

ということは popBackStack メソドは FragmentManager#popBackStack ということになるのか。ちなみに上記処理ですが、一連の処理に関する記述の和訳を @yanzm の中の人がエントリ投入されております。

でも上記な記述とはちょっと違う方法なのかなぁ。全部 Google のドキュメント確認した方が良さげ。以下?

  • getSupportFragmentManager
  • FragmentManager#popBackStack()
  • FragmentTransaction
  • FragmentManager#beginTransaction()
  • FragmentTransaction#replace()
  • onBeforeCommitReplaceFragment() メソド
    • BaseMultiPaneActivity で定義
      • 手続き定義は空
    • tablet.MapMultiPaneActivity で定義
    • tablet.ScheduleMultiPaneActivity で定義
  • FragmentTransaction#commit()

BackStack というナニが微妙に気になります。とりあえずそれは置いておいて上から順に確認していきましょうね。

getSupportFragmentManager

これ、getFragmentManager というメソドがあるようで、何がどう違うのか、と。内部定義かとも思ったのですがそうでもないみたいですし。
とりあえずこれ、FragmentActivity のメソドな模様。そういった意味では android.support.v4 なナニの範疇だな。あ、getSupport の support はソレって意味なのかな。
ちなみに getFragmentManager は android.support.v4.app.FragmentActivity には定義されていない模様です。

FragmentManager#popBackStack()

あ、早速 back stack が出てきましたね。これぶっちゃけると Fragment に表示されてるオブジェクトを stack に持ってて云々、なのかなぁ、と。たしか @yanzm さんのソレにも記述があったと記憶しております。xoom な iosched でも SessionDetail な Fragment からその前に表示されていた Sessions な Fragment に戻れたはず。
そりゃええんですが、てかイマサラ杉かもしれませんが以下必読ですな。

む、分かったぞ

ScheduleMultiPaneActivity#onSubstituteFragmentForActivityLaunch で以下な記述があるんスけど

        if (SessionsActivity.class.getName().equals(activityClassName)) {
            getSupportFragmentManager().popBackStack();

なんで popBackStack してるのか分からんかったのですが、別なセッション情報が表示されてて別なセッションのブロックをタタいた時、back stack は綺麗にしてあげる、という意図なのだろうと類推。

FragmentTransaction

ぼさっと @yanzm さんのナニを確認してたら以下な記述を発見。

すでに存在している Activity のレイアウトの ViewGroup にコードで入れる

FragmentTransaction を使う

なるほど。確かに layout-xlarge-v11/activity_schedule.xml 見てみたら fragment_container_schedule_detail な id が付けられてる View は FrameLayout になってます。
Fragment を ViewGroup に追加、な場合は

  • getSupportFragmentManager メソドで FragmentManager なオブジェクトを取得
  • FragmentManager#beginTransaction メソドで FragmentTransaction なオブジェクトを取得

して云々という処理が必要らしい。FragmentManager#beginTransaction メソドについてはスルーします。

FragmentTransaction#replace()

ええと http://d.android.com な記述によると以下。

Replace an existing fragment that was added to a container.

まあそのマンマですね。コンテナに追加されてなくても置き換える、という理解で良いのかどうか。

onBeforeCommitReplaceFragment() メソド

どんどん進めます。このメソドは以下で定義されてるみたい。

  • BaseMultiPaneActivity で定義
    • 手続き定義は空
  • tablet.MapMultiPaneActivity で定義
  • tablet.ScheduleMultiPaneActivity で定義

例えば ScheduleMultiPaneActivity な定義は以下です。

    protected void onBeforeCommitReplaceFragment(FragmentManager fm, FragmentTransaction ft,
            Fragment fragment) {
        super.onBeforeCommitReplaceFragment(fm, ft, fragment);
        if (fragment instanceof SessionDetailFragment) {
            ft.addToBackStack(null);
        } else if (fragment instanceof SessionsFragment) {
            fm.popBackStack();
        }
        updateBreadCrumb();
    }

これ、何をしてるんだろ。さっき似たようなことしてる記述を見た気がするが (ry
ええと FragmentTransaction#addToBackTrack メソドは Add this transaction to the back stack. とのことなので、SessionDetail だったら back stack に保存するのか。てーことは SessionDetail から別な Session 選んでも back したら Detail に戻れるのかなぁ。実機で動作見れるかなぁ。
あ、これ置き換えられる Fragment が stack に保存されるのか。実機で動作見てみたら SessionDetail なソレから Sessions なナニに戻れます。動作としてはこれがふつーですよね。Sessions 選択されたら popBackStack で破棄ってのも当たり前な挙動か。
参考まで @yanzm さんのナニ に記載されている addToBackStack な解説を引用しておきます。

addToBackStack() を呼ぶことで置換トランザクションがバックスタックに保存され、ユーザーはバックボタンを押すことでトランザクションをリバースして前のフラグメントに戻すことができる。

updateBreadCrumb

これは一体何でしょ。activity_schedule な記述が以下です。

        <LinearLayout android:orientation="vertical"
            android:layout_width="0dp"
            android:layout_height="fill_parent"
            android:layout_weight="1"
            android:layout_marginLeft="@dimen/activity_pane_spacing"
            android:padding="@dimen/detail_pane_padding"
            android:background="?android:attr/detailsElementBackground">
            <android.app.FragmentBreadCrumbs android:id="@+id/breadcrumbs"
                android:layout_height="@dimen/detail_breadcrumb_height"
                android:layout_width="fill_parent"
                android:gravity="center_vertical|left" />
            <FrameLayout android:id="@+id/fragment_container_schedule_detail"
                android:layout_width="fill_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:background="@drawable/empty_sessions_background" />
        </LinearLayout>

ええと、FragmentBreadCrumbs で調べてみれば良い?
android.app.FragmentBreadCrumbs でググッてみたのですが、bread crumbs ってパンくずリストのことなのかな。確かに上に Sessions | Session Information みたいな形で出力されていることを確認。ScheduleMultiPaneActivity のいっちゃん下に updateBreadCrumb メソドが定義されてます。

FragmentTransaction#commit()

@yanzm さんのナニに以下な記述があります。

FragmentTransaction に変更を加えたあとは、commit() を呼ばなければ反映されない。

宿題

以下。

  • act と dat で判断する模様 -> PackageManager#queryIntentActivities()
  • あと SessionDetail な Fragment でタブ使ってたけどあれは一体何だ

情報の洪水だorz

まとめ

これである程度情報とりまとめ可能かな。あと、iosched のクラス階層を転用するためにはどうすりゃ良いのか、を確認したい。