Androidアプリの4大要素 Activity
アプリケーションに複数のActivityがある場合は、そのうちのいずれか1つがアプリケーションのエントリーポイント(開始点)となり、AndroidのHOME画面からアプリのアイコンをクリックしたときに起動するActivityとなります。このエントリーポイントとなるActivityはマニフェストファイル(AndroidManifest.xml)で定義することができます。
では、HelloWorldアプリの唯一のActivityである、MainActivityを見てましょう。「src/com.example.helloworld/MainActivity.java」ファイルを開きます。
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
このように、Activityはandroid.app.Activityクラスを継承し作成します。
onCreate()メソッドをオーバーライドしていますが、これはのちほど詳しく紹介します。
継承するクラスはActivityでなくとも、そのサブクラスであれば問題ありません。
標準のActivityクラスだけでなく、特定の用途に合わせて拡張されたActivityクラスが提供されています。
クラス名 | 概要 |
---|---|
ListActivity | 一覧(ListView)の表示等を提供するよう拡張されたクラス |
MapActivity | 地図表示(MapView)の機能を利用するために拡張されたクラス |
PreferenceActivity | アプリケーションの設定情報を容易に扱えるように拡張されたクラス |
たとえば、ListActivityを継承することで一覧表示機能を持ったActivityを(通常のandroid.app.Activityを継承する場合に比べ)簡単に作成することができます。
すなわち、Activityなどのコンポーネントの生死をシステムが管理しているため、より優先度の高い他のアプリケーションでメモリが必要になった場合に、優先度が低いと判断されたコンポーネントは殺される(KILL)されてしまうことがあります。
また、KILLまではいかなくとも、他のアプリケーションやアクティビティが起動するなどによって、現在起動中のアクティビティが影響を受けることもあります。
たとえば、メールを書いている(読んでいる)最中に電話がかかってくるなどがあたります。起動中だったメールアプリがバックグラウンドになり、フォアグラウンドには電話アプリが表示されますよね。
このようにコンポーネントの状態が遷移していくことをライフサイクルと呼びます。
Androidのコンポーネントにおけるライフサイクルは、インスタンス作成から始まり破棄されたところで終了となります。
その間には、下図のように様々に状態を変化さていくことになります。
具体的には、メールを書いている最中に電話がかかってくる(フォアグラウンドからバックグラウンド)→電話が終わりメールアプリに戻ってくる(バックグランドからフォアグラウンド)という具合です。
Androidシステムはコンポーネントの状態が遷移したときにActivityに定義されている特定のメソッドを呼び出します。(詳細は後述。onCreate()メソッドやonResume()メソッドなどがあります。)
これにより状態が変化したときに行うべき処理をコーディングすることができる仕組みとなっています。
たとえば、先ほどのメール作成中に電話がかかってきたという例では、バックグラウンドに遷移する前に”書きかけのメール内容を一時的に保存しておく”などの処理をコーディングしておくわけですね。
Activityがライフサイクル中に遷移する状態は以下の3種類だけです。
状態名 | 概要 | 重要度 |
---|---|---|
実行中 (フォアグラウンド) |
画面に表示されている状態のこと。ユーザーが操作可能。 | 高 |
一時停止中 (ビジブル) |
ユーザーからは見えているが、操作は不可能な状態こと。 Acitivity上に、別のコンポーネントが表示されていて、上のコンポーネントが透明、もしくは画面全体を占有していない状態が、一時停止中である。 ダイアログが表示されているなどの状態のことで、あまり頻繁には発生しない。 |
中 |
停止中 (バックグラウンド) |
ユーザーからは見えない状態のこと。(別のアクティビティの下に隠れているため)ユーザーインターフェースを使用しての操作は不可能。 停止前の状態を保持しているが、他のコンポーネントでメモリが必要とされた場合、優先的に破棄される。 |
低 |
それぞれの状態には表のように重要度が決められています。実行中の場合はシステムによって強制終了することはありませんが、一時停止中や停止中の場合は、システムによって強制終了させられる場合があります。
また、停止中に状態遷移したからといってプロセスがKILLされるわけではなく、コンポーネントが破棄されるまではメモリ状に常駐し続けるということにも注意が必要です。
- onCreate()メソッド
- onStart()メソッド
- onRestart()メソッド
- onResume()メソッド
- onPause()メソッド
- onStop()メソッド
- onDestory()メソッド
それでは実際によく起こるシチュエーションの中で、どのように状態遷移およびコールバックメソッドの呼び出しが行われているか見ていきます。
”Android端末起動後、初めてHOME画面からアプリアイコンをクリックした”等のActivityが一度も起動していない状態からの状態遷移です。
ユーザーの操作ではなく、Androidシステムが勝手に他のActivityを起動する場合もあります。この結果として、Activityが停止中(目に見えない状態)に遷移します。
フォアグラウンドで実行していたアプリによっては、自動的に終了する場合があります。またここで重要な点は、電話アプリはそれほど重いアプリケーションでない(リソースを使わない)点です。
この場合は、図の右側ルートを通り、実行中に状態遷移します。
他のアプリ(シュミレーションゲーム等)で遊ぶために、HOMEボタンをクリックした。
シチュエーション2と同様ですが、ユーザーの操作でActivityを起動する場合もあります。この結果として、Activityが停止中(目に見えない状態)に遷移します。
ここで重要な点は、シュミレーションゲームはかなり重いアプリケーション(リソースをかなり消費する)点です。
この場合は、図の左側ルートを通ります。
その後、他のアプリ(シュミレーションゲーム等)を終了し、再度HOME画面よりActivityを起動した。
シチュエーション1とは、以前Activityを起動していたためタスクリスト(HOMEボタン長押し)上に表示されている点が異なります
「src/com.example.helloworld/MainActivity.java」を以下のように書き換えます。
public class MainActivity extends Activity { public static final String TAG = "ActivityLifecycle"; @Override public void onCreate(Bundle savedInstanceState) { Log.i(TAG, "onCreate() called."); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void onStart() { Log.i(TAG, "onStart() called."); super.onStart(); } @Override public void onRestart() { Log.i(TAG, "onRestart() called."); super.onRestart(); } @Override public void onResume() { Log.i(TAG, "onResume() called."); super.onResume(); } @Override public void onPause() { Log.i(TAG, "onPause() called."); super.onPause(); } @Override public void onStop() { Log.i(TAG, "onStop() called."); super.onStop(); } @Override public void onDestroy() { Log.i(TAG, "onDestory() called."); super.onDestroy(); } }
※見た目は”HelloWorld”プログラムと変わりありませんが、Activityのライフサイクルがわかりやすいように、コールバックメソッドにログ出力を行うロジックをいれてあります。
Androidが出力するログを参照するには、LogCatビューを使用します。
LogCatには、エミュレータやAndroid実機がエラー出力を行った場合のスタックトレース情報や、ログメッセージなどが表示されます。
LogCatビューはDDMSパースペクティブに含まれています。
ActivityLifecycleアプリケーションを起動していると、以下のようなメッセージが出力されているはずです。
Androidからは非常に大量のログが出力されるため、LogCatでは目的のログを探すためのフィルタリング機能が提供されています。
「Saved Filters」の”+”アイコンをクリックすることで、フィルタの設定が可能です。
LogCatビューで参照できるログを出力するには、android.util.Logクラスを使用します。このクラスにはログレベルに合わせたログ出力メソッドがそれぞれ用意されています。
ログレベル | メソッド名 | 概要 |
---|---|---|
ERROR | e | アプリケーションに致命的なエラーが発生した際に用いる |
WARN | w | アプリケーションに復旧可能なレベルのエラーが発生した際に用いる |
INFO | i | アプリケーション動作の情報を出力する際に用いる |
DEBUG | d | デバッグ情報を出力する際に用いる |
VERBOSE | v | 詳細なトレース情報を出力する際に用いる |
これらのメソッドはすべてLogクラスのstaticメソッドして定義されており、以下のようなシグネチャを持ちます。
public static int d (String tag, String msg)
第1引数にはLogCatに出力するタグを指定し、第2引数にはログメッセージを指定します。戻り値には書き出したログのバイト数が返ってきます。
なお、一般的にタグは定数として宣言しておくことが多いようです。
public static final String TAG = "ActivityLifecycle";