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

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

Activityライフサイクルの管理(3) Activityの停止と再開始

※本記事はhttp://developer.android.com/training/basics/activity-lifecycle/stopping.htmlの直訳です。
サンプルコードもそちらからダウンロードしてご利用下さい。


アプリケーションが常に生存しその進捗を失わないというユーザーの理解を保証するためにActivityのライフサイクル内でActivityを適切に停止(stop)、そして再開始(restart)することは重要なプロセスである。Activityが停止、再開始するなかでキーとなるいくつかのシナリオがある。

  • ユーザーが最近のアプリ一覧を開き、あなたのアプリを他のアプリに切り替えた。現在フォアグラウンドにいるあなたのアプリのActivityは停止される。もしユーザーがホームスクリーンのランチャーアイコンまたは最近のアプリ画面からアプリに戻ってきた場合、Activityは再開始する。
  • ユーザーがアプリ内で新しいActivityを開始するアクションを実行する。次のActivityが生成されると現在のActivityは停止される。ユーザーがバックボタンを押下すると最初のActivityは再開始される。
  • ユーザーが携帯端末でアプリを使用中に電話を受信する。

Activityの停止と再開始の間の制御を厳密に操作できるよう、ActivityクラスはonStop()とonRestart()の2つのライフサイクルメソッドを提供している。部分的なUIの遮断と同一視される一時停止(Paused)状態とは違って、停止(Stopped)状態はそのUIがもはや表示されておらず、ユーザーのフォーカスが分離されたActivity(または全体的に隔離されたアプリ)にあることが保証される。

システムは、Activityが停止されるとActivityのインスタンスをシステムメモリ内に維持するため、onStop()とonRestart()(またはonStart()メソッドでさえ)を実装する必要は無い。比較的シンプルなほとんどのActivityは、停止や再開始の場合でも、継続中のアクションの一時停止やシステムリソースの切断のためにonPause()を使うだけで良いかもしれない。

http://developer.android.com/images/training/basics/basic-lifecycle-stopped.png
図1:ユーザーがActivityを離れるとき、システムはActivityを停止するためにonStop()を呼ぶ(1)。もしユーザーが停止状態のActivityから戻る場合、システムはonRestart()を呼び(2)、直ちにonStart()(3)やonResume()(4)が続く。Activityが停止するケースのシナリオとは無関係に、システムは常にonStop()の前にonPause()を呼ぶことに注意。

Activityの停止

ActivityのonStop()メソッドが呼ばれると、それはもう表示されておらず、ユーザーがそれを使わない間に不必要なほとんど全てのリソースは解放されるべきである。一旦Activityが停止すると、システムはシステムメモリを回復する必要がある場合にそのインスタンスを破棄する場合がある。極端な場合、システムは単に最後のonDestroy()コールバックを呼ぶことなしにアプリのプロセスを終了するかもしれない。だから、メモリリークしそうなリソースはonStop()で解放することが重要である。

onPause()メソッドがonStop()の前に呼ばれるにもかかわらず、データベースに情報を書き込むようなCPU負荷の高い後処理はonStop()を使うべきである。

例えば、永続化領域に原稿の内容を保存するonStop()の実装がある。

@Override
protected void onStop() {
    super.onStop();  // Always call the superclass method first

    // Save the note's current draft, because the activity is stopping
    // and we want to be sure the current note progress isn't lost.
    ContentValues values = new ContentValues();
    values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
    values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());

    getContentResolver().update(
            mUri,    // The URI for the note to update.
            values,  // The map of column names and new values to apply to them.
            null,    // No SELECT criteria are used.
            null     // No WHERE columns are used.
            );
}

Activityが停止されると、Activityオブジェクトはメモリ内に常駐し、Activityが再開する際に再び呼び戻される。再開(resumed)状態になるまでのコールバックメソッドのいずれかで生成されたコンポーネントも再初期化の必要はない。システムはまたレイアウト内のそれぞれのViewに対して現在の状態を保持する。そのため、ユーザーがEditTextウィジェットに文字を入力した場合でもそのコンテンツは保ち続けるので、開発者がそれを保存したり元に戻す必要はない。

システムが停止中のActivityを破棄するときでさえ、Viewオブジェクトの状態はまだBundle内に維持され、ユーザーがActivityの同じインスタンスに戻ろうとするときに元の場所に戻す。

Activityの開始、再開始

Activityが停止状態からフォアグラウンドに戻ってくると、onRestart()が呼ばれる。システムはまた(再開されたか、最初に生成されたかのどちらかで)Activityが表示される度にonStart()メソッドを呼ぶ。onRestart()メソッドはしかしActivityが停止(stopped)状態から再開するときにだけ呼ばれるので、Activityが以前に停止されたが破棄されていないActivityで必要になるかもしれない特別な復元処理を実行することができる。

アプリがActivityの状態を復元するためにonRestart()を使う必要は滅多にないため、アプリの一般的な用途に適用するこのメソッドのガイドラインは無い。一方onStop()メソッドで基本的に全てのActivityのリソースを削除するべきであるから、Activityが再開始(restart)するときに再初期化する必要がある。けれどもまた、Activityが最初に生成されるときにも(Activityのインスタンスが存在しない場合は)初期化をする必要がある。この理由から、通常はonStart()コールバックをonStop()メソッドに対応するものとして使うべきである。なぜなら、システムはonStart()をActivityを生成するときと停止状態から再開始するときの両方で呼ぶからである。

例えば、ユーザーが戻ってくる前に長い時間アプリから離れている可能性があるため、onStart()メソッドはシステムの機能が有効になっているかどうかを確認するには良い場所である。

@Override
protected void onStart() {
    super.onStart();  // Always call the superclass method first
    
    // The activity is either being restarted or started for the first time
    // so this is where we should make sure that GPS is enabled
    LocationManager locationManager = 
            (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    
    if (!gpsEnabled) {
        // Create a dialog here that requests the user to enable GPS, and use an intent
        // with the android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS action
        // to take the user to the Settings screen to enable GPS when they click "OK"
    }
}

@Override
protected void onRestart() {
    super.onRestart();  // Always call the superclass method first
    
    // Activity being restarted from stopped state    
}

システムがActivityを停止するとき、ActivityのonDestroy()メソッドを呼ぶ。一般にほとんどのリソースはonStop()で解放するべきであるので、onDestory()が呼ばれるまでにアプリがするべきことはほとんどない。このメソッドはメモリーリークを引き起こしそうなリソースを解放する最後のチャンスであるので、追加のスレッドの破棄や他の長時間実行しているメソッド追跡のようなアクションもまた停止すべきである。