ActivityとFragmentの連携を理解する (Android Kotlin)

/




図のように2つのFragmentを1つのActivityで操作する簡単なサンプルプロジェクトを作ってみたのでまとめておく。




activity_main.xmlを用意する


まずFragmentを動的に追加するためのコンテナとして、空っぽの状態のレイアウトファイルを用意する。今回は1つだけしかActivityを使わないのでactivity_main.xmlを修正することにした。ConstraintLayoutidcontainerとしていることに注意しよう。




ActivityからFragmentを呼び出す


ActivityonCreateで最初に表示したいFragmentを設定するには次のようなコードを書くことになる。




ここではHogeFragmentクラスを用意することにした。HogeFragmentクラスの内容は次のとおりである。





HogeFragmentクラスでは、レイアウトファイルのonClick属性にメソッドを実装したかったのだが、実際にボタンを押すと次のようなエラーが出てしまった。

java.lang.IllegalStateException: Could not find method onButtonPressed(View) in a parent or ancestor Context for android:onClick attribute defined on view class android.support.v7.widget.AppCompatButton with id 'button'
        at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.resolveMethod(AppCompatViewInflater.java:424)
    


どうもHogeFragmentクラス内のメソッドを見つけてくれないようだ。仕方がないのでsetOnClickListenerでクラスに直接書き込むことにした。



このようにinflaterで生成したViewからfindViewByIdでボタンの参照を取得する。そしてsetOnClickListenerでボタンのクリックイベントを設定した。


Fragment内のViewにアクセスしたい


ところでFragment内のTextViewにアクセスしたい場合はどうすればよいだろうか?
最良の方法かどうかはわからないが、次のようにしてViewの参照を保持することで可能になった。考え方は先程のボタンイベントの設定のときと同じだ。




このTextViewを実装したのが次のFugaFragmentクラスである。





ActivityからFragmentへ値を渡す




このFugaFragmentにはcompanion objectというシングルトンの宣言がある。Android StudioFragmentを新規作成するときに、include fragment factory methods?にチェックを入れることでこのようにファクトリーメソッドが自動生成されるのだ。



ファクトリーメソッドを使ってActivityからFragmentを生成してみよう。

このようにファクトリーメソッドを使うことでFragmentActivityからパラメータを受けてることが出来る。


Fragmentの切り替えとバックスタックへ追加




FugeFragmentのボタンを押すとActivityonFugeFragmentAddFragment通知が届くようになっている。onFugeFragmentAddFragmentメソッドの中でFragmentFugaFragmentに切り替えてみることにしよう。次のように記述することでFragmentを切り替えることができる。




transaction.addToBackStack(null)の一行に注目しよう。この処理を書くことで、1つ前のHogeFragmentはバックスタックに積まれることになる。バックスタックに積んだことによって、FugaFragmentから1つ前のHogeFragmentへ戻ることが可能となるのだ。また端末の戻るボタンからも1つ前のFragmentへ戻ることができる。もしも戻ることを許可したくない場合にはaddToBackStackの一行を書かなければ良い。


ところでActivityFragmentのやり取りはインタフェースを介してやりとりしているが、ダイアログや[ネットワーク](https://www.101010.fun/entry/fragment-asynctask-networking)のサンプルでも説明してきたので今回は詳細は省略する。


1つ前のFragmentへ戻る




戻るときは簡単で、積んであるBackStackから(Popする)取り出せばよい。


BackStackからPopすると現在の表示されているFragmentonDetachが呼ばれ開放される。


まとめ


FragmentActivityのようなライフサイクルをもつ事ができるクラスだ。
Viewレイアウトをもつことも出来るが、[ネットワークサンプル](https://www.101010.fun/entry/fragment-asynctask-networking)で試したときのようにViewをまったく持たないFragmentも作ることが出来た。このことはFragment単位で様々な処理を分担できることを意味しており、つまりActivityからの制御を行いやすくすることができる。したがって重要な大まかな流れだけをActivityに書くことで、格段にメンテナンスがしやすくなるのだ。


今回のサンプルもまたGitHubへプッシュしておいたので参考に。
https://github.com/araemon/AndroidExercise/tree/master/TryFragment


参考


* フラグメント (Android Developers/ドキュメント/ガイド)
* Fragment上のonClickとかをFragment内で受け取る
* Fragmentでのイベントハンドリング
* FragmentのViewをいじってみる
* [Android] アクティビティ内で動的にフラグメントを生成してレイアウトに追加する


関連記事


非同期 & ネットワーク処理
* はじめてRetrofitを使ってみる (Android Kotlin)
* 非同期処理でCoroutine(コルーチン)を使ってみる (Android Kotlin)
* OkHttpでHTTP通信 (Android Kotlin)
* スレッド処理 (Android Kotlin)

View & レイアウト
* リサイクラービューを使ってリスト表示 (Android Kotlin)
* 角丸表現 (Android Kotlin)
* onSaveInstanceStateで画面回転時の状態の保存と復元 (Android Kotlin)
* ListViewを簡単なモデルで理解しよう (Android Kotlin)
* バネアニメーション (Android Kotlin)
* startActivityForResultを使ってみる (Android Kotlin)
* ActivityとFragmentの連携を理解する (Android Kotlin)
* DataBinding機能を使ってみる (Android Kotlin)
* タッチイベントのフック (Android Kotlin)
* DialogFragmentを使ったダイアログの表示 (Android Kotlin)

サウンド
* これってSoundPoolのバグ?(Android Kotlin)
* SoundPoolを使ってゲームの効果音を再生する (Android Kotlin)

データ & オブジェクト
* Kotlinでオブジェクト(object)の動作確認
*
データクラスとタプル (Android Kotlin)
* Null安全、ぬるぽバイバイ (Android Kotlin)