onSaveInstanceStateで画面回転時の状態の保存と復元 (Android Kotlin)

/




今回は下記の書籍のサンプルを元にフラグメントを2つ作って連携させ、さらにonSaveInstanceStateを使ったアクティビティの状態の復元を行った。



ButtonFragment


ButtonFragmentを次のようにして作成した。



ButtonFragmentfragmentに一つだけButtonをもつ。クリックイベントはインタフェースを介してホストアクティビティへ通知できるようにしている。


TextFragment


TextFragmentButtonFragmentでボタンがクリックされる毎にカウントアップを表示させるためのフラグメントだ。また、カウンターはファクトリーメソッドを使ってホストアクティビティから初期値を設定できるようにしている。



update()メソッドは後ほどMainActivityから呼び出すことになる。


Fragmentをレイアウトファイルに設置する


今回はButtonFragmentを直接レイアウトファイルに設置し、TextFragmentMainActivityから動的に設置する。

まずButtonFragmentを設置しよう。Paletteからfragmentを探してドラッグアンドドロップする。





図のようにlayout属性に@layout/fragment_buttonを忘れずに指定しよう。これを設定しないとコンパイルエラーとなってしまうのだ。


つぎにTextFragmentを動的に追加するためFrameLayoutを使ったコンテナを作成する。



このコンテナに動的にTextFragmentを追加するプログラムを見てみよう。MainActivityを次のように記述する。



注目すべきところはfragmentにTAGをつけてsupportFragmentManager.findFragmentByTagのように、どこからでも参照可能なようにしている。もし返り値がnullであるならば、まだフラグメントが生成されていないということなので、トランザクションを使用してフラグメントを新規作成している。




状態の保存


ここまでのプログラムを実際に実行してみよう。カウンターの初期値に100が表示され、ボタンをクリックする毎に1づつカウントアップされるのが確認できることだろう。

しかし画面を回転するとどうだろうか?カウントアップの表示が初期化されてしまった。



実は画面が回転されるとAndroidシステムがレイアウトの再ロードを行う必要があるために、アクティビティが破棄され再作成される仕様となっているのだ。このことはこちらに詳しく書かれているので参照したい。

アクティビティの再作成

そこで解決策の1つとしてonSaveInstanceState()コールバックメソッドを使った状態の保存を実装することにする。onSaveInstanceState()はアクティビティが破棄される前に呼び出されるメソッドだ。そのメソッド内でBundleオブジェクトを使った状態の保存を行う。保存した値はonCreate()またはonRestoreInstanceState()で受け取ることができる。


今回はカウンターの値を保存しておきたいので、TextFragmentに次のようにonSaveInstanceState()を実装した。



そしてonCreateメソッドを次のように書き換えた。


エルビス演算子を使ってsavedInstanceStateに値がなければargumentsから値を呼び出し、それでも値がなければカウンターに初期値として0を設定している。

この状態でプログラムを再度実行してみよう。ボタンを何回か押してカウントアップさせたあと画面を回転してみるとどうなるだろうか?見事カウントの値が保持されたまま再表示されることが確認できた。




まとめ


最後にこの記事で以下の内容を行ってきたことをおさらいしておこう。

* フラグメントからイベントをホストアクティビティに通知した。
* ファクトリーメソッドを使ってフラグメントへ初期値を渡した。
* フラグメントをTAGを使って管理した。
* アクティビティからフラグメントを動的に追加した。
* onSaveInstanceStateを使って画面回転時における状態の保存と復元を行った。



参考


* 基本からしっかり身につくAndroidアプリ開発入門 Android Studio 3対応 (「黒帯エンジニア」シリーズ)
* アクティビティの再作成


関連記事


非同期 & ネットワーク処理
* はじめてRetrofitを使ってみる (Android Kotlin)
* 非同期処理でCoroutine(コルーチン)を使ってみる (Android Kotlin)
* OkHttpでHTTP通信 (Android Kotlin)
* スレッド処理 (Android Kotlin)

View & レイアウト
* リサイクラービューを使ってリスト表示 (Android Kotlin)
* 角丸表現 (Android Kotlin)
* onSaveInstanceStateで画面回転時の状態の保存と復元 (Android Kotlin)
* ListViewを簡単なモデルで理解しよう (Android Kotlin)
* バネアニメーション (Android Kotlin)
* startActivityForResultを使ってみる (Android Kotlin)
* ActivityとFragmentの連携を理解する (Android Kotlin)
* DataBinding機能を使ってみる (Android Kotlin)
* タッチイベントのフック (Android Kotlin)
* DialogFragmentを使ったダイアログの表示 (Android Kotlin)

サウンド
* これってSoundPoolのバグ?(Android Kotlin)
* SoundPoolを使ってゲームの効果音を再生する (Android Kotlin)

データ & オブジェクト
* Kotlinでオブジェクト(object)の動作確認
*
データクラスとタプル (Android Kotlin)
* Null安全、ぬるぽバイバイ (Android Kotlin)