Hatena::ブログ(Diary)

_development, RSSフィード Twitter

2013-04-25

Activity.onAttachFragment() does not work with ChildFragmentManager

Fragment#getChildFragmentManager()で取得したFragmentManagerで管理しているFragmentはアタッチされても Activity.onAttachFragment(Fragment) が呼ばれないという話。

(尚、本エントリーの内容はサポートパッケージでしか現象の確認と調査を行っていません)


おしごとでChildFragmentManagerによるFragment in Fragmentで、このひと(Y.A.M の 雑記帳 Fragment in Fragment 時の注意点)とともにはまったのでメモ。


弊社ではAndroid開発にgoogle-guicedaggerなどのDIフレームワークを使っていまして、(はじめてのDependency Injection)でやっているようにライフサイクルメソッドのコールバックを作成して、コールバック内でインジェクションしています。


コールバックでやっている理由は、DIされるオブジェクト自身が自らDIコンテナのインジェクションメソッドを呼び出すよりも、コールバックを受け取った別の誰かがDIするほうが利点があるからで、それはいいとして、ともかく。

  • ActivityへのインジェクションはActivity.onCreate(Bundle)
  • FragmentへのインジェクションはActivity.onAttachFragment(Fragment)

でやっていたわけです。

しかし、ViewPagerを持つFragmentからChildFragmentManagerで管理されたViewPager内のFragmentでは、なぜかActivity.onAttachFragment(Fragment)がコールバックされないという現象が発生しました。

結果はご想像どおり、@Inject されるべきところに何もインジェクションされていないので、依存オブジェクトメソッド呼び出した瞬間、ぬるぽ ガッですよね。


というわけで、原因を追ってみました。


結論を言うと、FragmentManagaer.getChildFragmentManager()で取得したFragmentManagerに管理されたFragmentオブジェクトはmParentFragmentフィールドに親(そのFragmentを管理するためにFragmentManagaer.getChildFragmentManager()を呼び出したFragmentオブジェクト)が設定されています。

mParentFragmentフィールドに親が設定されていると、Activity.onAttachFragment(Fragment) は呼ばれません。


FragmentManagerの該当箇所のコードは次のようになっています。


if (f.mParentFragment == null) {
  mActivity.onAttachFragment(f);
}

仕方がないので、インジェクションするためのコールバックをActivity.onAttachFragment(Fragment)からFragment.attach(Activity)に変更して対応しました。


DIのためにActiviy.onAttachFragment(Fragment) を使わなくても、Fragmentのインスタンスの参照を得たり、リスナーをごにょごにょしたりするためにonAttachFragment(Fragment)を使っている人は注意が必要です。


以上です。