前人未踏の領域へ Androidアプリ開発編

Androidアプリ開発に関する調査メモ置き場。古い記事にはアプリ以外も含まれます。

Activityライフサイクルの管理(1) Activityの開始

本記事はAndroidトレーニング
http://developer.android.com/training/basics/activity-lifecycle/starting.html
の直訳です。

Activityの開始

main()メソッドでアプリが始まる他のプログラミングパラダイムとは違い、Androidシステムはそのライフサイクルの特定の状況に対応する特定のコールバックメソッドを呼び出すことによってActivityインスタンス内のコードを開始する。

Activityを開始するコールバックメソッドの順序とActivityを終了するコールバックメソッドの順序がある。

ライフサイクルコールバックについて理解する。

Anctivityが生きている間、システムは階段状のピラミッドに似たライフサイクルメソッドのコアセットを呼び出す。システムが新しいActivityのインスタンスを生成すると、それぞれのコールバックメソッドは頂上に向かって1ステップ状態を遷移する。ピラミッドの頂上はActivityがフォアグラウンドで動作していてユーザーがそれを操作できる地点である。
ユーザーがActivityを離れ始めるとシステムはActivityを破棄する為、ピラビッドを下りるAcitivity状態へ遷移する他のメソッドを呼び出す。いくつかのケースではActivityはピラミッドを下りる一つのルートにだけ遷移するか、待つ(ユーザーが他のアプリに切り替えたときのように)、Activityのポイントからトップに戻ることもユーザーが離れた位置から再開することもできる。

http://developer.android.com/images/training/basics/basic-lifecycle.png
Figure 1. A simplified illustration of the Activity lifecycle, expressed as a step pyramid. This shows how, for every callback used to take the activity a step toward the Resumed state at the top, there's a callback method that takes the activity a step down. The activity can also return to the resumed state from the Paused and Stopped state.

Acitivityの複雑さによってはおそらく全てのライフサイクルメソッドを実装する必要はない。しかしそれぞれを理解することと、ユーザーが期待するアプリの振る舞いを保証した実装をすることは重要である。以下のいくつかの方法でActivityのライフサイクルメソッドを実装することによりアプリの振る舞いを適切に保証する。

  • ユーザーが電話を受けるか、アプリの使用中に他のアプリに切り替えてもクラッシュしない
  • ユーザーがAnctivityを使用しない間、貴重なシステムリソースを消費しない
  • ユーザーがアプリを離れてしばらくして戻ってきてもその進捗を失わない
  • スクリーンが縦画面から横画面に回転してもクラッシュしないか、ユーザーの進捗を失わない。

以下のレッスンで異なる状態間をActivitiyが推移するいくつかのシチュエーションについて学ぶことになる。しかし、これらの状態のうち3つだけが静的である。つまり、Acitivityは長時間の間3つの状態のうち一つだけに存在することができる。

  • Resumed

この状態ではActivityはフォアアグラウンドにいてユーザーがそれを操作できる。

  • Paused

この状態ではActivityは別なAcitivityがフォアグウンドにいるが、半透明だったり、画面全体を覆っていなかったりするために部分的に見えなくなっている。一時停止状態のActivityはユーザーの入力を受け取らず、どのコードも実行することができない。

  • Stopped

この状態ではActivityは完全に隠れていてユーザーに表示されていない。すなわちバックグラウンドにいると考えられる。停止状態の間、Activityのインスタンスや全てのメンバー変数のようなその状態に関する全ての情報は保持される。しかし、どのコードも実行されない。

CreatedやStartedなどの他の状態は一時的であり、システムは次のライフサイクルのコールバックメソッドを呼び出し、すぐにそれらの状態から次の状態に遷移する。つまり、システムがonCreate()メソッドを呼んだあと、すぐにonStart()メソッドが呼ばれ、またすぐにonResume()メソッドに後を追われる。

これが基本的なライフサイクルである。いくつかの特定のライフサイクルの振る舞いについて学んでいく。

アプリのランチャーActivityを定義する。

ユーザーがホームスクリーンからアプリのアイコンを選択すると、システムはアプリ内で"ランチャー(またはmain)"として宣言されたAcitityのonCreate()メソッドを呼び出す。これがアプリとユーザー間の最初の入り口として機能するActivityとなる。

メインActivityとして使用するActivityはプロジェクトディレクトリルートにあるAndroid Manifestファイル(AndroidManifest.xml)で定義できる.
アプリのメインActivityはMAINアクションとLAUNCHERカテゴリを含むタグで定義される必要がある。

<activity android:name=".MainActivity" android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

Android SDK TooksでAndroidプロジェクトを新規作成した場合、マニフェスト内にこのフィルターで宣言されたActivityを含んだファイルがデフォルトで含まれている。

もしActivityのうち一つもMAINアクションかLAUNCHERカテゴリのどちらも宣言されていない場合、アプリアイコンはホームスクリーンのアプリ一覧に表示されない。

新しいインスタンスの作成

ほとんどのアプリはユーザーに異なるアクションを実行することを可能にするいくつかの異なるアクティビティを含む。Acitivityがユーザーがアイコンをクリックしたときに生成されたメインActivityかユーザーアクションに応じて開始した異なるActivityかに関わらず、システムはonCreate()メソッドを呼ぶことで毎回新しいActivityのインスタンスを生成する。

Activityの生存期間で一度だけ発生するべき基本的なアプリの開始ロジックを機能させるためにonCreate()メソッドを実装する必要がある。たとえば、onCreate()メソッドの実装はUIやいくつかの初期化可能なクラススコープ変数の定義をすべきである。

例えば以下のonCreate()の例ではUIの宣言、メンバー変数の定義、そしてUIのいくつかの設定といったActivityの基本となる初期設定を実行するコードを記述している。

TextView mTextView; // Member variable for text view in the layout

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Set the user interface layout for this Activity
    // The layout file is defined in the project res/layout/main_activity.xml file
    setContentView(R.layout.main_activity);
    
    // Initialize member TextView so we can manipulate it later
    mTextView = (TextView) findViewById(R.id.text_message);
    
    // Make sure we're running on Honeycomb or higher to use ActionBar APIs
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        // For the main activity, make sure the app icon in the action bar
        // does not behave as a button
        ActionBar actionBar = getActionBar();
        actionBar.setHomeButtonEnabled(false);
    }
}

新しいAPIを実行することから古いシステムを守るためにSDK_INTの使用はAndroid2.0(API Level5)以上でのみ動作する。より古いバージョンではランタイム例外に遭遇するだろう。

一度onCreate()の実行が終了するとシステムはすぐに連続してonStart()メソッドとonResume()メソッドを呼び出す。アクティビティは決してCreated(生成)やStarted(停止)状態には留まらない。テクニカルにはonStart()メソッドが呼ばれた時点でActivityがユーザーから見える状態になる。しかし、すぐにonResume()メソッドが続き、電話を受けたり、ユーザーが他のActivityに移動したり、端末のスクリーンがoffになったりといっった変化が起こるまでActivityはResumed(再開)状態のままでいる。

以下の他のレッスン内ではどのようにonStart()メソッドとonResume()メソッドが開始するか、PausedやStopped状態からアクティビティを再開するときのActivityのライフサイクル中に役立つかについて見ていく。

onCreate()メソッドは後のレッスンで議論する"savedInstanceState"と呼ばれるパラメータを含んでいる。

http://developer.android.com/images/training/basics/basic-lifecycle-create.png
Figure 2. Another illustration of the activity lifecycle structure with an emphasis on the three main callbacks that the system calls in sequence when creating a new instance of the activity: onCreate(), onStart(), and onResume(). Once this sequence of callbacks complete, the activity reaches the Resumed state where users can interact with the activity until they switch to a different activity.

Activityの破棄

Activityの最初のライフサイクルコールバックがonCrate()メソッドであるのと同時に、最後のコールバックがonDestroy()である。システムはAcitivityのインスタンスがシステムメモリーから完全に削除された最後のシグナルとしてActivityのこのメソッドを呼ぶ。

ほとんどのアプリではActivityのローカルクラスの参照が破棄されているため、このメソッドの実装を必要とせず、ActivityはonPause()メソッドかonStop()メソッド間でほとんどクリアするように処理すべきである。しかしAcitivityがonCreate()メソッドで作成したバックグラウンドスレッドか、おそらくクローズされていないメモリーリークの可能性がある他の長期間実行されているリソースを含む場合、onDestroy()で停止すべきである。

@Override
public void onDestroy() {
    super.onDestroy();  // Always call the superclass
    
    // Stop method tracing that the activity started during onCreate()
    android.os.Debug.stopMethodTracing();
}

システムはonCreate()内でfinish()が呼ばれた場合をのぞいた全ての状況でonPause()とonStop()が呼ばれた後にonDestroy()を呼ぶ。他のActivityを起動するための一時的なActivityとして使われるようないくつかのケースでは、onCreate()内でActivityを破棄するためにfinish()を呼ぶかもしれない。このケースではシステムは他のライフサイクルメソッドを呼ばずに、直ちにonDestroy()を呼ぶ