ActivityとFragmentの違い

前略: Activity と Fragment の使い分けがわからん!

「Androidのプロジェクトを作るとActivityもFragmentもセットで出来上がったりするけど、お互い似たような性質はあるし、結局どのような切り分けで使い分けたら良いかわからない!」という方向けに、それぞれの簡単な仕様や歴史を説明して、それぞれの役割を明確にするための参考情報なればいいなと。

Activity is

ライフサイクルを持ったUI兼UIコントローラー。
setContentViewで設定したレイアウトをUIとして使うことができる。
画面単位で使うのが一般的。
画面履歴をスタックで管理でき、バックで前のActivityに戻ることができる。この仕様は、Androidのタスク、起動モード、Activityバックスタックの仕様に密接に関係している。

Fragment is

ライフサイクルを持ったUI兼UIコントローラー。
onCreateViewで生成したViewをUIとして使うことができる。
今は画面単位で使うことが一般的。画面の一部分を表現したり、Fragment同士で親子関係を持つこともできたり、ライフサイクルに合わせたロジックだけを持つこともできるため、幅広い用途で使える。
スタック管理ができ、バックで前のFragmentに戻ることができ、このスタックはActivity(または親Fragment)が管理し、Androidのタスク、起動モード、Activityバックスタックの仕様とは関係ない。

Fragment誕生の経緯と有用性

Fragmentは、Tablet用に作られたAndroid3.0から、よりフレキシブルなUI実現のためにActivity上のUIの断片化を目的として生まれた。
そのためレイアウト内にどのように配置するかという点でも、Viewのように扱えるように設計されている。
これにより、ActivityだけではやりづらかったTab機能やActionBarなど、実際にさまざまなUIを実現しやすくなった。
ライフサイクル管理の難しさや、クラスも3種類(※)もあって紛らわしかったりプログラマを躓かせる要素は多く、Fragment反対論もあったが、今は Android Architecture Components (NavigationConmponentやLifeCycleなど)の登場や kotlin-android-extentions(2020以降は非推奨) によって使いやすくなっている。
※Fragment3兄弟:
長男 android.app.Fragment
次男 android.support.v4.app.Fragment
年の離れた三男 androidx.fragment.app.Fragment

ViewはFragmentの代わりにならないのか?

単純に、ViewをFragmentの代わりにできないのか?という話です。
ViewはActivityと連動するようなライフサイクルを持たないため、Activityのライフサイクルと連動する必要のある処理を作ろうとすると、ActivityからViewにライフサイクル完了と終了を通知する仕組みを考えなければならず、相当しんどいです。代わりにならないことはないですが、相当しんどいですので、代わりにならないといっても過言ではないです。

タスクとActivityバックスタックの呪縛からの解放

Fragmentができる前までは、Activityのスタック管理が Android の「タスクとバックスタック」管理の仕様と密接に関係しているため、設定を間違えるとバックで戻ったときなどに意図しない画面遷移をしてしまうというような、アプリ間遷移を考慮したアプリ内画面遷移の設計の難しさの問題がありました。
Android は、タスクにActivityを積む仕組みで履歴を管理しているが、このタスクというのはアプリに閉じているわけではありません。
別のアプリのActivityも同じタスクに積んだり、同じアプリでも別のタスクとして積むことができます。
これは、インストールされたapkのActivity(公開されている)というのは Android からみればただのパッケージ名を持ったActivityの集合でしかなく、どのアプリかという厳密な枠組みは持たずに、設定値に準じてスタック管理する仕様だからです。(どういう意図かはわかりませんが。)
基本的には同一パッケージ名のActivityがスタックされていく仕様ですが、UIUX検討の中で細かい設定を入れざるを得ない場合があり、そういったときにはどうしてもこの問題にぶつかります。(例えばとあるサービスを利用するためのライブラリが提供するそのサービスのログインUIのActivityが、アプリのActivtiyの起動モードの方針と違う設定で、ライブラリを使う部分だけアプリの意図しない遷移を実現できてしまい、バグの要因になる、とか。抽象的でわかりにくい例かもしれないですが。。。)
しかし、FragmentスタックはActivity(または親Fragment)が管理しておりアプリに閉じているため、アプリ内でOSのタスク仕様に依存しないスタック管理がしやすくなりました。

Activity神格化からの解放

プレゼンテーションロジックがActivityに集約されがちで、神オブジェクト化し人間が手を出せなくなることは珍しくありませんでしたが、Fragmentができてから処理が分散され軽減されました。
また、今では、MVPアーキテクチャ、MVVMアーキテクチャ、クリーンアーキテクチャなどのアーキテクチャパターンをアプリに適用することで、プレゼンテーションロジックを持つクラスはFragmentとは別に管理しようとすることが主流です。

まとめ

こういった理由から(他にもあると思うけど)、ActivityもFragmentの似たような性質はあるけど、Fragmentを使うことで以下の利点が出てきます。

  • Activityが神オブジェクトから開放され、コードの可読性があがる
  • フレキシブルなUIUXを提供しやすくなる
  • Activityのスタック仕様を意識しなくてよくなる

ただし、似たような性質があるので役割を明確にしないとチーム開発では混乱を招きますので役割を明確にするのがよいと思います。
個人的には↓のように切り分けるのが好みです。

  • Activity は Fragment をコントロールする
  • Fragment がUIをコントロールする
  • Activity はアプリ全般(アプリのフォアグラウンド・バックグラウンド)のライフサイクルを管理する
  • Fragmentには画面単位のライフサイクルを管理する

以上です!

参考

Activity起動モード仕様参考- **激参考になる**:

  • https://itnext.io/the-android-launchmode-animated-cheatsheet-6657e5dd9b0f
  • https://developer.android.com/guide/components/activities/tasks-and-back-stack?hl=ja
  • https://developer.android.com/guide/topics/fundamentals?hl=ja#acttask

Fragmentに関する参考

  • https://qiita.com/glayash/items/1da7a4c879e02f47e04
  • https://developer.android.com/guide/components/fragments

kiyoshi.saito@tttsunagari.jp

アプリ開発をメインにWebアプリ開発をやってるフリーランスエンジニアです。

Leave a Reply

Your email address will not be published. Required fields are marked *