はじめに
本記事ではAndroidアプリ開発におけるフラグメント(Fragment)の概念と、アプリ開発に重要なライフサイクル、実際にどうやって使うのか等を説明しています。
フラグメント(Fragment)
フラグメント(Fragment)とは
フラグメント(Fragment)とはアプリUIの再利用可能な部分を作ることが出来るビューです。Activityと比較すると、フラグメント(Fragment)はそれぞれの細かな単位でのレイアウトを定義して管理することができます。以下Fragmentと呼びます。
また、ライフサイクルも持ち合わせているため、様々な制御が可能であったり、入力イベントの処理も行うことができます。
Fragmentの位置付けとしてはUIの部品なので、常にActivityの子ビューとして構成する必要があり、Fragment単体では表示することはありません。良く使われる例としては、以下の図の構成があげられます。
この例では、Activityという大きな枠に、「ホーム」ボタンと「設定」ボタンを配置しています。
「ホーム」ボタンと「設定」ボタンを押すと同時に、上部の「ホームFragment」と「設定Fragment」を切り替えるようなUIで、各FragmentがActivityからは独立しているので、Fragmentという1つのUI部品を再利用したり、修正したりすることが容易になります。
また、Activityに依存していないため、複数のActivityから呼び出すことができます。そのため、再利用可能なコンポーネントにすることができます。Activityで画面を作成した場合には、その画面は別のActivityでは利用できませんので、Fragmentを利用するほうが汎用性が高まります。
Fragmentのライフサイクル
続いてライフサイクルについて説明します。
前回Activityのライフサイクルについて説明しましたが、Activityと同様にFragmentもライフサイクルを持っており、ライフサイクルを意識した開発をする必要があります。
※Activityのライフサイクルがわからない方は下記をご覧ください。
下記画像はGoogleが出している、Fragmentの公式ライフサイクル。詳しく見てみましょう。
Activityと同じ部分コールバック関数は省略しますが、Fragmentのライフサイクルで重要な点としてはonAttach(),onCreateView(),onActivityCreated(),onDestoyView(),onDetach()です。
Fragmentは前項で説明したように、単体で動作することはなく常にActivityの子ビューとして動作するため、AttachとDetach、英語を翻訳すると「付いた」「取り外された」という概念が存在します。
Fragment自身からしてみれば、Activityに付けられた時点でUIが作成され、取り外された時点でUIを破棄しなければいけないので、破棄された時点でデータの保存や消去をしておく必要があります。下記は各コールバック関数の説明になります。
onAttach() | ActivityによってFragmentが取り付けられた タイミングで呼び出されるコールバック関数 | |
onCreateView() | Fragment内のUIを描画するタイミングで 呼び出される関数 | |
onActivityCreated() | Activity内のonCreate()が完了した際に呼び出される コールバック関数 | |
onDestoyView() | FragmentのUI(View)が破棄されたタイミングで 呼び出されるコールバック関数 | |
onDetach() | ActivityによってFragmentが取り外された タイミングで呼び出されるコールバック関数 |
よく利用されるやり方としては、onCreate()でフラグメントのコンポーネントの初期化や設定値の初期化を行い、onCreateView()でUIを描画するためのViewを返します。その後、onPause()やonStop()でデータや設定値などを保存しておくのが良いです。
FragmentManagerとは
FragmentManagerとはその名通り、Fragmentを管理するためのクラスで、ActivityからFragmentの追加/削除/置換/バックスタックなどを検知し制御を行うためのクラスです。
応用例としては、Activityの子ビューとして Fragmentを使うだけでなく、Fragmentの子ビュー、つまり、Activity→Fragment→Fragmentのような構成も作ることが出来るため、この場合にはFragmentクラス内でFragmentManagerを呼び出すことが必要となります。
FragmentTransactionとは
FragmentTransactionとは、FragmentManagerでは各Fragmentに対して管理が出来るのに対して、FragmentTransactionは実際にActivityにFragmentを追加するためにcommit(コミット)を実行したり、Fragmentの入れ替えを行ったりすることが出来るクラスです。
使い方としてはFragmentTranasctionでFragmentを表示させたり、バックスタックに移動させたりして、FragmentManagerで状態を管理します。
Fragmentの利用例
Fragmentの呼び出し
ここでは実際にActivityからどうやってFragmentを呼び出すかKotlinのソースコードを確認してみましょう。SampleFragmentというFragmentを作り、Activity内にcontainerというidのFrameLayoutを配置しています。
supportFragmentManager.beginTransaction()
.replace(R.id.container,SampleFragment())
.setReorderingAllowed(true)
.addToBackStack("name")
.commit()
上記の例では、supportFragmentMangerでFragmentManagerクラスを呼び出し、beginTransaction()関数でFragmentTransactionを取得しています。その後、replace関数でcontainerというidのFrameLayoutにSampleFragmentを配置するという処理です。
また、setReorderingAllowedはFragmentの状態変更を最適化するためのもので、addToBackStackではユーザーが「戻る」ボタンを押すことにより、1つ前のFragmentに戻ることができるようになる設定です。最後に、.commit()で上記の設定を実行しています。
拡張できるサブクラス(DialogFragment,ListFragment)
Fragmentはそのものを拡張(extends)することができますが、既に色々な用途で利用するための拡張クラスが用意されています。今回はDialogFragmentとListFragmentを紹介します。
ソースコードの無駄を減らしたり、開発期間を短縮するためには、できるだけ車輪の再発明はせず、既に利用できるものをどんどんつかっていきましょう!
DialogFragment
DialogFragmentとは、よくあるアプリであるような警告画面やお知らせ画面などのダイアログを出すためのFragmentです。こちらを利用することダイアログのカスタマイズが簡単に行えるようになります。
ListFragment
ListFragmentとは、例えば求人情報のリストや、動画リストなど様々なリストを作るためのFragmentで、リスト型のUIを利用するときは、このListFragmentをカスタマイズすると簡単に作れるようになります。
FragmentとActivity間での通信
続いてFragmentとActivityの間でデータのやりとり(通信)を行う方法について説明します。例えばFragmentでユーザーが入力したユーザー情報を、Fragmentが破棄された後にもActivityでも利用したい場合などが挙げられます。
このような場合に、データや情報を渡すためにインターフェース(interface)を作りましょう。インターフェース(interface)とはその名の通り、特定のコンポーネント同士の橋渡しになるような通り道/トンネルのようなものを作るための機能です。
コードの書き方としては、FragmentとActivity側の両方に「データを送る処理」と「データを受け取る処理」を記述する必要があります。まずFragmentの方から見ていきましょう。
var listener: OnInputUserNameListener? = null
interface OnInputUserNameListener {
fun onInputUserName(name: String)
}
上記の例では、ユーザー名を入力する時をイメージしており、OnInputUserNameListenerというインターフェイスを作成しています。このインターフェースの中にはonInputedUserNameという関数が用意されており、この関数を実行することでインターフェースを通して情報を伝えることが可能になります。
続いてonInputedUserNameを実行するために、ユーザーの名前を入力するときに、この関数を実行させます。
listener?.onInputedUserName("なまえ")
最後に、Activity側でFragment内に作成した、OnInputUserNameListenerのインターフェースを継承(implements)して、onInputedUserNameコールバック関数を作成します。。
override fun onInputedUserName(name: String) {
//Fragmentでユーザーの名前が入力されると、このコールバック関数が呼び出される
}
このようにすると、Fragment側でユーザー名をが入力された時に、onInputedUserName関数が実行され、それと同時にActivity側のonInputedUserNameコールバック関数も実行され、FragmentのデータをActivityに受け渡すことが可能になります。
まとめ
今回はFragmentの基本として、Fragmentの概念やライフサイクル、インターフェースを作成したデータの受け渡し方法などを説明しました。
今までの知識を利用して、下記記事では実際にFragmentを利用したタブアプリケーションの実装を説明しています。、一般的によくあるタブ付きのアプリで画面の切り替えや、ライフサイクルを意識したアプリを作ってみたいと思います。