Android アプリ開発の入門書を手に取ると、まず画面の作成に始まり、必要な部品を追加してメソッドを実装し、他の画面への遷移へと順に進む方針で書かれていることが一般的です。
そこでは基本的にアクティビティ (Activity) というコンポーネントを使用することを前提に話が進みます。
- アクティビティ | Android Developers
- https://developer.android.com/guide/components/activities.html?hl=ja
アクティビティは私のような初心者にも直感的に理解しやすく、書籍などの情報量も多いので、当然と言えば当然なのかもしれません。
一方で現在の Android アプリ開発では、入門書の例のようにアクティビティをふんだんに用いて実装を行うのではなく、より小さなフラグメント (Fragment) というコンポーネントを利用して、個々のアクティビティの役割を少なくする考えが主流になっています。
- フラグメント | Android Developers
- https://developer.android.com/guide/components/fragments.html?hl=ja
その背景にはアクティビティの役割が増えすぎて肥大化していたことや、異なる画面の大きさを持つ多くの機器への対応などが挙げられていますが、本題ではない上に長くなるので割愛します。
重要なことは、一般的な Android アプリ開発では多用されているフラグメントについて、アプリ開発の入門段階では使い方を知る術が限られていることです。
たとえインターネット上には豊富に情報があったとしても、知らないものは調べられないのです。
フラグメントを使用するとタブの切り替えによる画面表示の変更などを簡単に実装できます。
それどころか、入門書で作成しているサンプルアプリではアクティビティほど多用な機能は必要ない場合も多いので、フラグメントのみで画面遷移を実現できる場合も少なくありません。
フラグメントの簡単な使用方法はアクティビティ同様に、Java ファイルと XML ファイルを用意してアクティビティに追加してあげることです。
例えば Java ファイルを FooFragment.java として、その内容を以下のようにしてやれば、他に必要なことは2点のみです。
1 2 3 4 5 6 7 8 9 10 |
public class FooFragment extends Fragment { /* 省略 */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_foo, container, false); // view.findViewById() などで何かする場合にはここに実装 return view; } } |
1点目はコード中の R.layout.fragment_foo で参照されている XML ファイル fragment_foo.xml を作成してあげること。
1 2 3 4 5 6 7 8 9 |
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="info.femoghalvfems.sample.FooFragment"> <!-- 省略 --> </android.support.constraint.ConstraintLayout> |
もう1点目は作成したフラグメントをアクティビティに追加してあげることです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class MainActivity extends FragmentActivity implements FooFragment.OnFragmentInteractionListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); FooFragment fragment = new FooFragment(); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.add(R.id.layout_activity_main, fragment); transaction.commit(); } } |
この時、追加するフラグメントの OnFragmentInteractionListener を実装してあげないと InflateException を吐いてアプリが落ちますので、忘れずに実装してください。
InflateException は他のエラーと同様に Android Monitor の logcat から確認できます。
1 2 3 4 5 6 7 |
E/AndroidRuntime: FATAL EXCEPTION: main Process: info.femoghalvfems.sample, PID: 13994 java.lang.RuntimeException: Unable to start activity ComponentInfo{info.femoghlavfems.sample/info.femoghalvfems.sample.MainActivity}: android.view.InflateException: Binary XML file line #12: Binary XML file line #12: Error inflating class fragment ### 省略 ### Caused by: java.lang.RuntimeException: info.femoghlavfems.sample.MainActivity@87ac4dd must implement OnFragmentInteractionListener |
これでうまくビルドに成功すれば、アプリの立ち上げ画面からフラグメントのレイアウトを表示するようになります。
レイアウトを切り替えるにはフラグメントから FragmentManager を利用します。
1 2 3 4 5 6 7 8 9 |
public class FooFragment extends Fragment implements View.OnClickListener { /* 省略 */ @Override public void onClick(View v) { FragmentManager manager = getActivity().getSupportFragmentManager(); manager.beginTransaction().replace(R.id.layout_activity_main, BarFragment.newInstance("", "")).addToBackStack(null).commit(); } } |
この時に忘れてはならないのは、追加されるアクティビティ (ここでは MainActivity) に追加するフラグメント (ここでは BarFragment) の OnFragmentInteractionListener を追加実装してあげることです。
このようにアクティビティと比較するとやや煩雑になってしまいますが、入門書で作成したサンプルアプリを使ってアクティビティからフラグメントを使用した構成に自分でコードを書き換えていくと、アプリ開発についての理解が深まって良い勉強になります。
そしてあまり入門書では触れられていない、FragmentTabHost を用いたタブの切り替えも簡単に行えるようになる点も見逃せません。