ページ

2013/11/14

[Android]FragmentからActivityへのイベントの通知方法

Fragment から Activity へのイベントの通知方法のベストな方法を紹介します。
@vvakameさんの CallbackPicker のことなんですが、
文書化されていないようなので記事を書いておきます。
CallbackPicker よりも CallbackProvider の方が
なんとなくしっくり来たので勝手に名前を変えました。

とりあえず以下の方法を理解していることが前提です。
Y.A.M の 雑記帳: Fragment から Activity にコールバックする方法
リンク先の内容を簡単に説明すると、
onAttach で activity がリスナーを実装しているかチェックしてコールバックメソッドを呼ぼう!ってことです。

今回の方法はその方法を1段深くしたような形になっています。
public class MainActivity extends FragmentActivity implements MainFragmnetCallbackProvider {

    @Override
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);

        MainFragment fragment = MainFragment.newInstance();
        getFragmentManager().beginTransaction().add(android.R.id.content, fragment, MainFragment.TAG).commit();
    }

    @Override
    public MainFragmnetCallback getMainFragmnetCallback(){
        return new MainFragmnetCallback(){
            @Override
            public void onAttach(MainFragmnet mainFragmnet){

            }
        }
    }
}
public class MainFragment extends Fragment {

    public static final String   TAG = MainFragment.class.getSimpleName();
    private MainFragmentCallback mCallback;

    public static interface MainFragmentCallbackProvider {

        public MainFragmentCallback getMainCallback();

    }

    public static interface MainFragmentCallback {

        public void onAttach(MainFragment mainFragment);

    }

    public static MainFragment newInstance(){
        MainFragment fragment = new MainFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onAttach(Activity activity){
        super.onAttach(activity);

        if(activity instanceof MainFragmentCallbackProvider == false){
            throw new ClassCastException(activity.getLocalClassName() + " must implements " + MainFragmentCallbackProvider.class.getSimpleName());
        }
        MainFragmentCallbackProvider provider = (MainFragmentCallbackProvider)activity;
        mCallback = provider.getMainCallback();
        mCallback.onAttach(this);
    }

}
MainFragment に2つの interface を用意して Activity で MainFragmnetCallbackProvider を実装します。
MainFragmnetCallbackProvider は MainFragmentCallback を返す getMainCallback() のみを提供します。
getMainCallback() で MainFragmentCallback を 匿名インナークラスとして書いてあげれば
MainFragment に関するイベントはその匿名インナークラス内に集約されます(←重要!※)。
あとは MainFragment で MainFragmentCallback のメソッド宣言に好きなコールバックを書いてあげるだけ!

※ MainFragmnetCallbackProvider を使うことでコールバックメソッドのスコープが小さくなるから便利ですよ!
MainFragment のちょっとしたリスナーだけだったらいいかもしれないけど
MainActivity で 他にも Fragment を扱ったりするとコールバックメソッドが入り乱れて見難くなります。
7, 8個くらい Fragment を Activity にくっつけたときはコレじゃなかったら可読性低くて大変だったかも。

interface の名前的に自由にコールバックメソッドを追加しやすかったのも良いと思いました。
Fragment 同士の連携も Activity に一旦コールバックして
Activity から Fragment のメソッド実行すれば良いので
お互いの実装に関わりを持たずにコールバックを投げておけば良いというのも開発しやすいポイントです。

この MainFragment は Fragment クラスの拡張を作る際のテンプレにしておきたいので記事を書きました。