Tips

Androidアプリの4大要素とインテント Activity 【Android Tips】

Androidアプリの4大要素 Activity

1
Androidアプリの4大要素とインテント
Androidアプリの4大要素 Activity
この節では、Androidアプリケーションの4大要素のうちの1つ”Activity”を紹介します。Activityはユーザーとアプリケーションとの間で行われるやり取り全般を仲介し、「1つの画面」を表す単位です。
Activity概要
ActivityはAndroidアプリケーションの4大要素のうちの1つで、他には”Service”、”ContentProvider”、”BroadcastReceiver”があります。Activityはユーザーとアプリケーションとの間で行われるやり取り全般を仲介し、「1つの画面」を表す単位です。ただし、Activity単体ではユーザーの目には見えず、画面のレイアウトや画面を構成する部品(ウィジェット)を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のライフサイクル
Androidでは、ハードウェアリソース(メモリや記憶領域)の管理はAndroidシステム側が行います。
すなわち、Activityなどのコンポーネントの生死をシステムが管理しているため、より優先度の高い他のアプリケーションでメモリが必要になった場合に、優先度が低いと判断されたコンポーネントは殺される(KILL)されてしまうことがあります。
また、KILLまではいかなくとも、他のアプリケーションやアクティビティが起動するなどによって、現在起動中のアクティビティが影響を受けることもあります。
たとえば、メールを書いている(読んでいる)最中に電話がかかってくるなどがあたります。起動中だったメールアプリがバックグラウンドになり、フォアグラウンドには電話アプリが表示されますよね。
このようにコンポーネントの状態が遷移していくことをライフサイクルと呼びます。

 

Androidのコンポーネントにおけるライフサイクルは、インスタンス作成から始まり破棄されたところで終了となります。
その間には、下図のように様々に状態を変化さていくことになります。


具体的には、メールを書いている最中に電話がかかってくる(フォアグラウンドからバックグラウンド)→電話が終わりメールアプリに戻ってくる(バックグランドからフォアグラウンド)という具合です。

 

Androidシステムはコンポーネントの状態が遷移したときにActivityに定義されている特定のメソッドを呼び出します。(詳細は後述。onCreate()メソッドやonResume()メソッドなどがあります。)
これにより状態が変化したときに行うべき処理をコーディングすることができる仕組みとなっています。
たとえば、先ほどのメール作成中に電話がかかってきたという例では、バックグラウンドに遷移する前に”書きかけのメール内容を一時的に保存しておく”などの処理をコーディングしておくわけですね。

 

Activityがライフサイクル中に遷移する状態は以下の3種類だけです。

状態名 概要 重要度
実行中
(フォアグラウンド)
画面に表示されている状態のこと。ユーザーが操作可能。
一時停止中
(ビジブル)
ユーザーからは見えているが、操作は不可能な状態こと。
Acitivity上に、別のコンポーネントが表示されていて、上のコンポーネントが透明、もしくは画面全体を占有していない状態が、一時停止中である。
ダイアログが表示されているなどの状態のことで、あまり頻繁には発生しない。
停止中
(バックグラウンド)
ユーザーからは見えない状態のこと。(別のアクティビティの下に隠れているため)ユーザーインターフェースを使用しての操作は不可能。
停止前の状態を保持しているが、他のコンポーネントでメモリが必要とされた場合、優先的に破棄される。
 

それぞれの状態には表のように重要度が決められています。実行中の場合はシステムによって強制終了することはありませんが、一時停止中や停止中の場合は、システムによって強制終了させられる場合があります。
また、停止中に状態遷移したからといってプロセスがKILLされるわけではなく、コンポーネントが破棄されるまではメモリ状に常駐し続けるということにも注意が必要です。

Activityの状態遷移とコールバックメソッド
Activityの状態は3種類しかありませんが、状態遷移に応じて呼び出されるメソッド(コールバックメソッド)は全部で7種類あります。

  • onCreate()メソッド
  • onStart()メソッド
  • onRestart()メソッド
  • onResume()メソッド
  • onPause()メソッド
  • onStop()メソッド
  • onDestory()メソッド

これらのメソッドが呼び出されるタイミングは下図のようになります。

濃い赤色が実行中、中程度の赤色が一時停止中、薄い赤色が停止中の状態を表す。

たとえば、Activityが初めて起動するとき(Android端末起動後、初めてHOME画面からアプリアイコンをクリックした等)は、開始→onCreate()→onStart()→onResume()→実行中と全部で3種類のコールバックメソッドが呼び出されます。これでActivityがフォアグラウンドになったことになります。

 

それでは実際によく起こるシチュエーションの中で、どのように状態遷移およびコールバックメソッドの呼び出しが行われているか見ていきます。

■シチュエーション1■ Activityを初めて起動した。
”Android端末起動後、初めてHOME画面からアプリアイコンをクリックした”等のActivityが一度も起動していない状態からの状態遷移です。

開始すると”停止中”→”一時停止中”→”実行中”と状態遷移し、onCreate()→onStart()→onResume()と3種類のメソッドが実行される。

■シチュエーション2■ その後、電話がかかってきたため、Activityがバックグラウンドに遷移した。
ユーザーの操作ではなく、Androidシステムが勝手に他のActivityを起動する場合もあります。この結果として、Activityが停止中(目に見えない状態)に遷移します。

”実行中”→”一時停止中”→”停止中”と状態遷移し、onPause()→onStop()と2種類のメソッドが実行される。

■シチュエーション3■ その後、電話が終わり(自動的に)Activityがフォアグラウンドに戻ってきた。
フォアグラウンドで実行していたアプリによっては、自動的に終了する場合があります。またここで重要な点は、電話アプリはそれほど重いアプリケーションでない(リソースを使わない)点です。
この場合は、図の右側ルートを通り、実行中に状態遷移します。

”停止中”→”一時停止中”→”実行中”と状態遷移し、onRestart()→onStart()→onResume()と3種類のメソッドが実行される。

シチュエーション1の場合と異なり、onCreate()が呼び出されない代わりにonRestart()が呼び出されています。

 

■シチュエーション4■
他のアプリ(シュミレーションゲーム等)で遊ぶために、HOMEボタンをクリックした。
シチュエーション2と同様ですが、ユーザーの操作でActivityを起動する場合もあります。この結果として、Activityが停止中(目に見えない状態)に遷移します。

”実行中”→”一時停止中”→”停止中”と状態遷移し、onPause()→onStop()と2種類のメソッドが実行される。

■シチュエーション5■ 他のアプリ(シュミレーションゲーム等)アイコンをクリックししばらく遊んだ。
ここで重要な点は、シュミレーションゲームはかなり重いアプリケーション(リソースをかなり消費する)点です。
この場合は、図の左側ルートを通ります。

リソース不足を補うために、Androidシステムは優先度の低いActivity(停止中のActivityなど)をKILLします。

■シチュエーション6■
その後、他のアプリ(シュミレーションゲーム等)を終了し、再度HOME画面よりActivityを起動した。
シチュエーション1とは、以前Activityを起動していたためタスクリスト(HOMEボタン長押し)上に表示されている点が異なります


開始すると”停止中”→”一時停止中”→”実行中”と状態遷移し、onCreate()→onStart()→onResume()と3種類のメソッドが実行される。

シチュエーション5によりプロセスがKILLされているためメモリ上にはインスタンスが存在していない状態です。そのため、再度onCreate()から実行されていきます。

Activityのライフサイクルとログ出力
では、コールバックメソッドが呼び出される様子を確認してみましょう。

「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パースペクティブに含まれています。

 

DDMSパースペクティブの起動方法

Eclipseメニューのウィンドウ→パースペクティブを開く→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";

Androidアプリ開発の必須知識!JAVAプログラミングを学べる連載リンク

はじめてのJAVA 連載

Recent News

Recent Tips

Tag Search