Androidでは画面を回転させると画面の向きに合わせたレイアウトを読み込もうとしてアクティビティを再構築(onDestory→onCreate)します。
アクティビティが再構築されるとその画面で入力された値などがクリアされてしまうため、対策を行う必要があります。
対策としては以下の4つの方法があります(俺が知る限りでは…)
・アクティビティの設定変化をハンドリング
・画面の向きを固定化
・Bundleに設定(一時保存)
・SQLiteやPreferenceなどへの保存(永続保存)
最後のSQLiteやPreferenceなどへの保存は画面の回転に限った話ではないので今回は除外します。
以下、その他3つの設定方法です。
参考サイト:ソフトウェア技術ドキュメントを勝手に翻訳 - 7.3 実行時の変化への対処
【アクティビティの設定変化をハンドリング】
アクティビティの設定の変更ハンドリングを宣言することで、画面の再構築を行わないようにします。
ハンドリングは、AndroidManifestのタグに android:configChanges を指定するとできます。
ハンドリングされた設定が変更されたとき Activity#onConfigurationChanged(Configuration newConfig) が呼ばれます。
変更時に何か処理が必要な場合は、このメソッドをオーバーライドして処理を記述してください。
AndroidManifest.xml
android:screenOrientation
"orientation" ユーザーがデバイスを回転させた
"keyboardHidden" キーボードへのアクセスが変更された
画面が回転されたときなので orientation を設定するだけでいいのですが、エミュレータなどでは keyboardHidden の設定も行わなければ再構築が発生してしまうので注意してください。
【画面の向きを固定化】
画面を縦、または、横に固定することでアクティビティの再構築を行わないようにします。
画面の固定は、AndroidManifestのタグに android:screenOrientation を指定するとできます。
AndroidManifest.xml
android:screenOrientation
"landscape" 横向き
"portrait" 縦向き
※ 一部端末(エミュレータ含む)では画面を回転させたときに keyboardHidden が呼ばれてしまうため再構築が行われてしまいます。
前述の【アクティビティの設定変化をハンドリング】にて android:configChanges="keyboardHidden" の設定を追加する必要があります。
【Bundleに設定】
Androidのライフサイクルではアクティビティが破棄されるとき、そのときの状態を保存するために onSaveInstanceState(Bundle outState) が呼び出されます。
このメソッドの引数の Bundle に値を設定することで破棄されるアクティビティの状態を一時的に保持することができます。
Bundleに設定された状態は、再構築後に呼ばれる onRestoreInstanceState(Bundle savedInstanceState) または onCreate(Bundle savedInstanceState) の引数のBundleから取得することができます。
なお、再構築時に呼ばれるライフサイクルの順番は以下のようになります(エミュレータで確認)
onSaveInstanceState() → onPause() → onStop() → onDestroy() → onCreate() → onStart() → onRestoreInstanceState() → onResume()
アクティビティのライフサイクルを考えるとコレ(Bundle)が正しい手法だと思われますが、ネットでは最初に紹介した【アクティビティの設定変化をハンドリング】を利用している方が多く見られます。
縦横でレイアウトを分けるのならともかく、分けないのであれば設定一つで終わるハンドリングが楽でいいですね。
Bundleは面倒なので俺もこちらを使っています。
アクティビティが再構築されるとその画面で入力された値などがクリアされてしまうため、対策を行う必要があります。
対策としては以下の4つの方法があります(俺が知る限りでは…)
・アクティビティの設定変化をハンドリング
・画面の向きを固定化
・Bundleに設定(一時保存)
・SQLiteやPreferenceなどへの保存(永続保存)
最後のSQLiteやPreferenceなどへの保存は画面の回転に限った話ではないので今回は除外します。
以下、その他3つの設定方法です。
参考サイト:ソフトウェア技術ドキュメントを勝手に翻訳 - 7.3 実行時の変化への対処
【アクティビティの設定変化をハンドリング】
アクティビティの設定の変更ハンドリングを宣言することで、画面の再構築を行わないようにします。
ハンドリングは、AndroidManifestの
ハンドリングされた設定が変更されたとき Activity#onConfigurationChanged(Configuration newConfig) が呼ばれます。
変更時に何か処理が必要な場合は、このメソッドをオーバーライドして処理を記述してください。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jp.inujirushi.sample"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="@drawable/icon"
android:label="@string/app_name">
<activity
android:configChanges="orientation|keyboardHidden"
android:label="@string/app_name"
android:name="SampleActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
android:screenOrientation
"orientation" ユーザーがデバイスを回転させた
"keyboardHidden" キーボードへのアクセスが変更された
画面が回転されたときなので orientation を設定するだけでいいのですが、エミュレータなどでは keyboardHidden の設定も行わなければ再構築が発生してしまうので注意してください。
【画面の向きを固定化】
画面を縦、または、横に固定することでアクティビティの再構築を行わないようにします。
画面の固定は、AndroidManifestの
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jp.inujirushi.sample"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="@drawable/icon"
android:label="@string/app_name">
<activity
android:label="@string/app_name"
android:name="SampleActivity"
android:screenOrientation="portrait" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
android:screenOrientation
"landscape" 横向き
"portrait" 縦向き
※ 一部端末(エミュレータ含む)では画面を回転させたときに keyboardHidden が呼ばれてしまうため再構築が行われてしまいます。
前述の【アクティビティの設定変化をハンドリング】にて android:configChanges="keyboardHidden" の設定を追加する必要があります。
【Bundleに設定】
Androidのライフサイクルではアクティビティが破棄されるとき、そのときの状態を保存するために onSaveInstanceState(Bundle outState) が呼び出されます。
このメソッドの引数の Bundle に値を設定することで破棄されるアクティビティの状態を一時的に保持することができます。
Bundleに設定された状態は、再構築後に呼ばれる onRestoreInstanceState(Bundle savedInstanceState) または onCreate(Bundle savedInstanceState) の引数のBundleから取得することができます。
package jp.inujirushi.sample;
import android.app.Activity;
import android.os.Bundle;
import android.text.Editable;
import android.widget.EditText;
import android.widget.LinearLayout;
public class SampleActivity extends Activity {
/** EditTextのID */
private static final int ID_EDIT = 1;
/** EditTextのキー */
private static final String KEY_EDIT = "text";
/** アクティビティを生成した時に呼ばれます。 */
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// サンプル用のレイアウトを生成する
LinearLayout layout = new LinearLayout(this);
EditText editText = new EditText(this);
editText.setId(ID_EDIT);
layout.addView(editText);
// レイアウトを画面に設定する
setContentView(layout);
//// 再構築時に前の状態に戻す
//if (savedInstanceState != null) {
// // Bundleに保存した値を取得する
// String value = savedInstanceState.getString(KEY_EDIT);
// // EditTextに値を設定する
// editText.setText(value);
//}
}
/** アクティビティがデータを一時保存する時に呼ばれます。 */
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// EditTextの値を取得する
EditText editText = (EditText) findViewById(ID_EDIT);
Editable value = editText.getText();
// Bundleに値を保存する
outState.putString(KEY_EDIT, value.toString());
}
/** アクティビティが一時保存されたデータを読み込む時に呼ばれます。 */
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Bundleに保存した値を取得する
String value = savedInstanceState.getString(KEY_EDIT);
// EditTextに値を設定する
EditText editText = (EditText) findViewById(ID_EDIT);
editText.setText(value);
}
}
なお、再構築時に呼ばれるライフサイクルの順番は以下のようになります(エミュレータで確認)
onSaveInstanceState() → onPause() → onStop() → onDestroy() → onCreate() → onStart() → onRestoreInstanceState() → onResume()
アクティビティのライフサイクルを考えるとコレ(Bundle)が正しい手法だと思われますが、ネットでは最初に紹介した【アクティビティの設定変化をハンドリング】を利用している方が多く見られます。
縦横でレイアウトを分けるのならともかく、分けないのであれば設定一つで終わるハンドリングが楽でいいですね。
Bundleは面倒なので俺もこちらを使っています。
スポンサーサイト
少し遅れましたが、新年明けましておめでとうございます。
当ブログは今後もAndroidプログラミングに関した記事を書いていきます。
今年こそは何かしたアプリの紹介やらを書けたらいいなーと思っています。
Tips的な記事もチラホラ書いているのですが、過去記事修正とかブログではやりづらい面もあるのでやっぱりホームページ持った方がいいのだろうかと考え中です。
まあ、ここで書くものはネットで検索するか本買えば終わるようなものばかりなのですが…。
何はともあれ、ブログのPingのおかげで一見さん 来訪者もそこそこおられるようなので少しでも役立てる記事を書けたらと思います。
今後ともよろしくお願いいたします。
当ブログは今後もAndroidプログラミングに関した記事を書いていきます。
今年こそは何かしたアプリの紹介やらを書けたらいいなーと思っています。
Tips的な記事もチラホラ書いているのですが、過去記事修正とかブログではやりづらい面もあるのでやっぱりホームページ持った方がいいのだろうかと考え中です。
まあ、ここで書くものはネットで検索するか本買えば終わるようなものばかりなのですが…。
何はともあれ、ブログのPingのおかげで
今後ともよろしくお願いいたします。