カテゴリー
Kotlin言語

ゼロから始めるAndroidアプリ(Kotlin編)Unit3 – 1 第4回 中編:ライフサイクルの状態

Android Developers > スタートガイド > Kotlin と Android をゼロから学ぶ > Unit3 – ナビゲーションUnit3-1 第4回 中編 の内容をまとめたものです(翻訳ではありません)


Unit3 – 1 第4回 中編

ライフサイクルの状態の変化を調べてみる

いろいろな操作パターンを試して、出力されるログを観察してみますね

  • DessertClicker アプリをいろいろな方法で使って、ログを観察してみます
  • アプリの使用に合わせて、ライフサイクルのコールバックがどんな風に起動するのか見てみます

その1:アクティビティを開いたり閉じたりしてみる

はじめてアプリを起動したとき、そしてアプリを完全に閉じたときのログを調べてみます

アプリを起動する

はじめて起動するときですね

  • DessertClickerアプリをビルドして実行します
  • アクティビティが初めて起動すると、onCreate(), onStart(), onResume() コールバックが順に呼ばれています
2020-10-16 10:27:33.244 22064-22064/com.example.android.dessertclicker D/MainActivity: onCreate Called
2020-10-16 10:27:33.453 22064-22064/com.example.android.dessertclicker D/MainActivity: onStart Called
2020-10-16 10:27:33.454 22064-22064/com.example.android.dessertclicker D/MainActivity: onResume Called

アプリの Back ボタン(◀)をタップする

  • 画面のカップケーキを何度かタップしてみます
  • デバイスのBackボタンをタップします
  • Logcat に onPause(), onStop(), onDestroy() が順に呼ばれています
2020-10-16 10:31:53.850 22064-22064/com.example.android.dessertclicker D/MainActivity: onPause Called
2020-10-16 10:31:54.620 22064-22064/com.example.android.dessertclicker D/MainActivity: onStop Called
2020-10-16 10:31:54.622 22064-22064/com.example.android.dessertclicker D/MainActivity: onDestroy Called

BACKボタンだと終了しちゃうんです

  • デバイスの Back ボタンを使うとアクティビティ(とアプリ)は完全に閉じられます
  • onDestroy() メソッドが実行されたあとアクティビティは完全に終了し、ガベージコレクション(Garbage collection)の対象になります
    • ガベージコレクションはオブジェクトの自動クリーンアップ処理です。ユーザが直接使うことはありません
  • コードの中でアクティビティの finish() メソッドを呼ぶことでも、アクティビティを完全にシャットダウンできます
    • finish() をつかうとユーザーによって強制終了(force-quit)できるアプリを作ることができます
  • Android システムは、アプリが長い間画面に表示されていない場合、アクティビティをシャットダウンすることができます
    • Android はこれによってバッテリの消費を抑えます
    • また、使っていないアプリのリソースをほかのアプリで使えるようにします

デバイスの ■ ボタンでアプリに戻る

  • Android の Overview screen(recent screen , recent app , オーバービュー画面 , 最近の画面)で、開いているすべてのアプリから DessertClicker アプリを探して戻ります
  • Logcat にはこんな感じに表示されます
2020-10-16 10:31:54.622 22064-22064/com.example.android.dessertclicker D/MainActivity: onDestroy Called
2020-10-16 10:38:00.733 22064-22064/com.example.android.dessertclicker D/MainActivity: onCreate Called
2020-10-16 10:38:00.787 22064-22064/com.example.android.dessertclicker D/MainActivity: onStart Called
2020-10-16 10:38:00.788 22064-22064/com.example.android.dessertclicker D/MainActivity: onResume Called

じつは新たに起動してるんですね

  • アクティビティは前のステップで破棄(Destroyed)されています
  • アプリに戻るために Android は新しいアクティビティを起動します。onCreate() , onStart() , onResume() メソッドを順に呼んでいます
  • 以前のアクティビティで DessertClicker に設定された値は保持されず、リセットされています

この操作でのポイント

  • onCreate() と onDestroy() は一つのアクティビティインスタンスのライフタイムの中で一度しか呼ばれません
  • onCreate() が呼ばれるのは一番最初にアプリを初期化するとき、onDestroy() はアプリで使われていたリソースをクリーンアップするときです
  • すべては onCreate() で初期化されるところから始まります
    • レイアウトのインスタンスはこの中でXMLから生成(inflate)されます
    • いろいろな変数がここで初期化されます

その2:アクティビティから出たり、戻ったりしてみる

こんどは違う画面に移動してみますね

  • 実際にAndroidデバイスを使うときには、アプリは完全には閉じられず、そのまま他のアプリ(アクティビティ)に移ったり、また戻ってきたりします
  • 電話のようなアプリが割り込んでくることもあります
  • アクティビティが画面から見えなくなったとき、アクティビティはバックグラウンド(background)にいる、と言います
  • 逆の状態をフォアグラウンド(foreground)、あるいはオンスクリーン(on screen)と言います
  • ユーザが元のアプリに戻ろうとすると、同じアクティビティが呼ばれて再び画面に表示されます(アプリの visible lifecycle と呼ばれます)
  • アプリがバックグラウンドにあるときは、通常、あまり動作をさせないようにします
    • システムリソースを有効に活用したり、バッテリーを長持ちさせたりするためです
  • ここでは、アプリがバックグラウンドに移動して、再びフォアグラウンドへ戻ったとき、アクティビティのライフサイクルがどうなるのか見てみます

デバイスの HOME ボタン(●)をタップする

  • DessertClicker アプリを起動して、カップケーキを何度かタップします
  • デバイスの Home ボタンをタップして Android Studio の Logcat を観察します
  • ホーム画面に戻っているとき、アプリは完全には終了しておらずバックグラウンドに移動しています
  • ログを確認すると onPause() と onStop() は呼ばれているけれども onDestroy() は呼ばれていません
2020-10-16 10:41:05.383 22064-22064/com.example.android.dessertclicker D/MainActivity: onPause Called
2020-10-16 10:41:05.966 22064-22064/com.example.android.dessertclicker D/MainActivity: onStop Called

ウラで待機してるんですね

  • onPause() が呼ばれると、アプリはフォーカスを失います(画面上の操作を受け付けなくなります)
  • onStop() のあと、アプリは画面から消えます(見えなくなります)
  • アクティビティは止まっていますが、Activity オブジェクトはまだメモリにあり、バックグラウンドで控えています。アクティビティは破棄されていません
  • ユーザはアプリに戻るかもしれず、Androidはアクティビティのリソースなどを維持しています

デバイスの ■ ボタンでアプリに戻る

  • ■ボタン(最近の画面)をタップしてアプリに戻ります
  • Logcat を見ると、アクティビティが onRestart() と onStart() を経て最後に onResume() で復帰しています
2020-10-16 10:42:18.144 22064-22064/com.example.android.dessertclicker D/MainActivity: onRestart Called
2020-10-16 10:42:18.158 22064-22064/com.example.android.dessertclicker D/MainActivity: onStart Called
2020-10-16 10:42:18.158 22064-22064/com.example.android.dessertclicker D/MainActivity: onResume Called

ウラからオモテに戻ってくる感じかも

  • アクティビティがフォアグラウンドに戻るとき、onCreate() メソッドは呼ばれません
    • アクティビティオブジェクトは破棄されておらず、あらためて生成する必要はないからです
  • onCreate() のかわりに onRestart() メソッドが呼ばれます
  • アクティビティは元のままなので、フォアグラウンドに戻ったとき、Desserts Sold(デザートの販売数)の値はちゃんと保持されています

他のアプリに移動してから元に戻る

  • DessertClicker の他に1つ以上のアプリを起動しておきます
    • デバイスの「最近の画面」にいくつかのアプリが表示されるようにするためです
  • 「最近の画面」を表示して、他のアクティビティを開きます
  • もういちど「最近の画面」に戻り、DessertClicker をフォアグラウンドに戻します
  • Logcat に表示されるコールバックは、Home ボタンを押したときと同じになります
    • アプリがバックグラウンドに行くときは onPause() , onStop() が呼ばれます
    • アプリに戻ってくるときは onRestart() , onStart() , onResume() が呼ばれます

やっぱりウラからオモテに戻るだけなんですね

この操作でのポイント

  • onStart() と onStop() は、ユーザがアクティビティを行ったり来たりするたびに呼ばれます
  • これらのメソッドは、アプリがバックグラウンドに動いたり、フォアグラウンドに戻されたりしたときに呼ばれます
  • バックグラウンドとフォアグラウンドの間を移動するときにしたい処理があれば、これらのメソッドをオーバーライドして記述します
  • onRestart() メソッドは onCreate() に似ており、どちらもアクティビティが見えるようになる前に呼ばれます
  • onCreate() メソッドは最初に Created の状態にするときにだけ呼ばれ、そのあとは onRestart() が呼ばれます

その3:部分的に隠れているアクティビティ

画面にダイアログが開くようなときですね

  • アプリが全画面表示されてフォーカスをもち、ユーザが操作できるようなライフサイクルの状態を、インタラクティブライフサイクル(interactive lifecycle)といいます
  • アプリがバックグラウンドにいくとき、まず onPause() が実行されたあとフォーカスが失われ、さらに onStop() が実行されたあと画面から見えなくなります
  • 画面表示とフォーカスが別になっていることで、アクティビティを画面上に一部だけ表示したまま、ユーザーフォーカスを持たないようにできます
  • アクティビティが部分的に見えるけれど、ユーザーフォーカスは持たないようなケースを見てみます

アプリのShareボタンでダイアログを表示

  • DessertClicker アプリを実行して、画面の右上のほうにあるShareボタンをクリックします
  • シェアのためのアクティビティが画面の下半分に現れますが、元のアクティビティがまだ上半分に表示されています
  • Logcat を見てみます。onPause() だけが呼ばれていることを確認します
2020-10-16 11:00:53.857 22064-22064/com.example.android.dessertclicker D/MainActivity: onPause Called

Started のところで止まってるみたい

  • 今回の場合、onStop() は呼ばれておらず、元のアクティビティはまだ部分的に見えている状態です
  • ただしフォーカスを持たないため、ユーザが元のアクティビティを操作することはできません
  • フォアグラウンドにあるのは “Share” アクティビティであり、こちらがフォーカスを持っています

この操作でのポイント

  • onPause() だけによる割り込みは、通常、比較的すぐに元のアクティビティに戻ったり、あるいは他のアプリに移動したりする場合に使われます
  • UI画面を更新せずに表示したままにすると、アプリがフリーズしたように見えてしまうことがあります
  • onPause() の中に記述するコードはできるだけ軽い処理にしておきます
    • onPause() の中の処理が重いと、たとえば電話が入ったとき電話の着信のお知らせが遅れてしまう恐れがあります
  • アプリに戻るのに “Share” ダイアログから外れたところをタップすると onResume() が呼ばれます
  • onResume() はアクティビティがフォーカスを持つときに呼ばれ、onPause() はアクティビティがフォーカスを失うときに呼ばれます

3つの操作パターンを試してみました。ほかにもいろいろ試してみてくださいね