【Kotlin/Android】onSaveInstanceStateの使い方!Activityの再生成

【Kotlin/Android】onSaveInstanceStateの使い方!Activityの再生成

この記事からわかること

  • Android Studio/KotlinonSaveInstanceStateとは?
  • ActivityFragment破棄された場合に再生成する方法
  • デバッグする方法

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

参考文献:AndroidアプリにおけるUIの状態保存と復元について調べてみた

ActivityやFragmentは破棄される

AndroidアプリではActivityやFragmentは一定の条件を満たすと破棄されてしまいます。破棄されるとUIの状態がリセットされ、表示するために取得したデータなども空になってしまいます。

破棄されるタイミングはイメージしやすいユーザー操作による別画面への移動やfinishの呼び出しなどだけでなく、画面の回転やメモリの使用状況などに応じてシステムからActivityが破棄されることがあります。

ActivityやFragmentの破棄を想定した実装にしていないとViewの再生成が行われなかったり、表示していたデータがリセットされてしまったりと予期せぬバグを引き起こす可能性があります。

そのためにActivityやFragmentのライフサイクルを理解し、データを適切に保存して再利用することが重要になります。

破棄されるタイミング

UIの再構築

UIを適切に再構築するためには各ライフサイクルで適切にUIが構築されるように実装する必要があります。といっても破棄された場合はライフサイクルが最初から呼ばれるだけなので下手な分岐処理さえ挟まなければ問題なく表示はされると思います。

Activityでいうとシステムによって破棄されたタイミングでonDestroyが呼ばれ再度生成されるタイミングでonCreate()が呼ばれます。

データの保存

APIやローカルから取得して表示していたデータなども破棄されてしまうのでデータを再度取得する処理の実装が必要になります。例えばユーザーが入力した値など一時的な値もリセットされてしまうのでここは以下の方法で回避することができます。

それぞれにメリット/デメリットがあるので使い分けは公式ドキュメントに記載の以下の表を確認すると分かりやすいです。

ViewModel 保存済みインスタンスの状態 永続ストレージ
保存先 メモリ内 メモリ内 ディスクまたはネットワーク上
構成変更後も保持
システムによるプロセス終了後も保持 ×
ユーザーによるアクティビティ終了/onFinish() も保持 × ×
データの上限 複雑なオブジェクトは問題ないが、使用可能なメモリによってスペースが制限される プリミティブ型と String などのシンプルな小さなオブジェクトのみ ネットワーク リソースからのディスク スペースまたはネットワークからの取得コスト / 時間によってのみ制限される
読み取り / 書き込み時間 高速(メモリアクセスのみ) 低速(シリアル化 / シリアル化解除が必要) 低速(ディスク アクセスまたはネットワーク トランザクションが必要)

引用:公式リファレンス:Options for preserving UI stat

ViewModel

永続ストレージ

今回はonSaveInstanceStateに焦点を当ててみたいと思います。

onSaveInstanceState

onSaveInstanceState状態を保存するために使用されるライフサイクルメソッドです。呼び出されるタイミングはActivityやFragmentが破棄される直前です。ライフサイクルに合わせて出力してみると以下の通りになりました。

onCreate
onStart
onResume
------- 破棄 -------
onPause
onSaveInstanceState
onStop
onDestroy
------- 復帰 -------
onCreate
onStart
onRestoreInstanceState
onResume

onSaveInstanceState内でBundleにデータを保存する処理を実装することでデータを保持しておき、ActivityやFragmentが復帰した際に避難させておいたデータをBundleから取得することができるようになります。

private val KEY_TEXT = "KEY_TEXT"
override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    // データの保存
    outState.putString(KEY_TEXT, textValue)
}

Bundleのデータ取得や保存方法は以下の記事を参考にしてください。

onRestoreInstanceState

データの取得はonRestoreInstanceStateまたはonCreateのどちらかからBundle経由で取得することができます。

override fun onRestoreInstanceState(savedInstanceState: Bundle) {
    super.onRestoreInstanceState(savedInstanceState)
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // データの復元
    if (savedInstanceState != null) {
        textValue = savedInstanceState.getString(KEY_TEXT)
    }
}

Activity/Fragmentの破棄をデバッグする

ActivityやFragmentが破棄される挙動を再現したい場合は端末を開発者モードに変更して「アクティビティを保持しない」にチェックを入れておくとアプリが停止するタイミングで破棄されるようにすることができます。

【Kotlin/Android】onSaveInstanceStateの使い方!Activityの再生成

開発者モードへの変更方法は以下の記事を参考にしてください。

Activityの再生成を無効化する

公式リファレンス:アクティビティの再作成を制限する

特定の構成変更に関してはActivityの自動再作成を制御することが可能です。「AndroidManifest.xml」ファイルのactivityエントリでandroid:configChangesを追加し、生成性を無効にしたい値を指定します。

<activity
    android:name=".MyActivity"
    android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
    android:label="@string/app_name">

指定できる値

属性 説明
colorMode 画面の色モード機能(色域またはダイナミックレンジ)が変更されました。アクティビティで使用しているカラーモードを変更しても、ディスプレイのカラー機能は変更されません。
density 表示密度の変更(ユーザーが異なるディスプレイスケールまたは別のディスプレイがアクティブになったとき)。API レベル 24 で追加されました。
fontScale フォントのスケーリングファクタの変更(ユーザーが新しいグローバルフォントサイズを選択したときなど)。
fontWeightAdjustment フォントの太さの増加量が変更されました。
grammaticalGender 言語の文法上の性別が変更されました。GrammaticalInflectionManager。API レベル 34 で追加されました。
keyboard キーボードの種類の変更(ユーザーが外部キーボードを接続したときなど)。
keyboardHidden キーボードのユーザー補助の変更(ユーザーがハードウェアキーボードを表示したときなど)。
layoutDirection レイアウト方向の変更(左から右(LTR)から右から左(RTL)に変更する)。API レベル 17 で追加されました。
locale ロケールの変更(ユーザーがテキストを表示する新しい言語を選択したときなど)。
mcc IMSI モバイルカントリーコード(MCC)の変更(MCC を更新する SIM が検出された場合)。
mnc IMSI モバイルネットワークコード(MNC)の変更(MNC を更新する SIM が検出された場合)。
navigation ナビゲーションタイプ(トラックボールまたは D-pad)への TA の変更。通常、このようなことは起こりません。
orientation 画面方向の変更(ユーザーがデバイスを回転させたときなど)。アプリが Android 3.2(API レベル 13)以上を対象としている場合は、"screenLayout" と "screenSize" の構成も宣言します。
screenLayout 画面レイアウトの変更(別のディスプレイがアクティブになったときなど)。
screenSize 現在使用可能な画面サイズの変更。ユーザーが横向きと縦向きを切り替えると変わります。API レベル 13 で追加されました。
smallestScreenSize 物理画面サイズの変更。向きに関係なくサイズが変更されたことを表しています。API レベル 13 で追加されました。
touchscreen タッチスクリーンの変更。通常、このようなことは起こりません。
uiMode ユーザーインターフェースモードの変更(ユーザーがデバイスをデスクやカーホルダーに置いたとき、夜間モードが変更されたときなど)。API レベル 8 で追加されました。

公式リファレンス:android:configChanges

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index