AndroidのActivityは再作成に備えてSavedInstanceStateを使おう

Activityは一度破棄されて再作成されるというプロセスを辿ることが意外とあります。

例えば端末を傾けた時、縦画面だった Activity は破棄されて横画面用の Activity が再作成されたり。

他にも、他のアプリを起動してバックグラウンドに行ったときメモリの状況によっては Activity が破棄される事があります。

 

Activityは破棄され再作成されるものと思ってコーディングする必要があります。

やるべき事

画面を回転させたり、言語設定を変えたり、メモリの空き状況など OS の都合によって Activity は破棄されて再作成されます。

(ライフサイクルに従って onDestroy() まで走って破棄され、新たな Activity が onCreate() から始まります)

 

OS の都合で再作成されたとしても、アプリとしてはさっきの続きとして動作させなければなりません。

作業中の内容を一時的に保存し、再作成後の Activity で正しく復元してあげる必要があります。

Viewは勝手にやってくれている

「作業内容の保存と復元なんてやってないけどちゃんと動いてるよ?」と思うかもしれません。

例えば EditText で入力中の文字など、画面を回転させた後も同じ状態になっています。

 

これはViewクラスが破棄時の保存と再作成後の復元をやってくれているからです。

つまり、View以外のデータは自分で保存・復元を行わなければいけません。

メンバ変数の保存・復元を実装しよう

自分で保存・復元を実装しなければならない物といえば Activity のメンバ変数です。

アプリ操作の過程でメンバ変数の値が変わる場合には、再作成後のActivityへ正しく引き継がなくてはいけません。

 

値の引き継ぎは Bundleクラスを使って行われます。

Activity が破棄される直前に onSaveInstanceState メソッドが呼び出されるので、そこで Bundle オブジェクトへ値を保存します。この Bundle オブジェクトは再作成後の Activity の onCreate メソッドもしくは onRestoreInstanceState メソッドへ渡されます。

Activityサンプル

public class LoginActivity extends Activity {
    private boolean mTest = true;
    private int     mNum  = 0;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);

        if (null != savedInstanceState) {
            mTest = savedInstanceState.getBoolean("Test");
            mNum  = savedInstanceState.getInt("Num");
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putBoolean("Test", mTest);
        savedInstanceState.putBoolean("Num", mNum);
    }
}

onSaveInstanceStateメソッドでメンバ変数をキーと結び付けて保存しています。

onCreateメソッドではキーを使って値を取り出しメンバ変数を復元しています。

メンバ変数がクラスの場合はSerializableにすると楽

保存したメンバ変数が int や String などならいいですのですが、時には自分で作ったクラスな時もあると思います。そんな時はクラスを Serializable にしておくと保存・復元が楽になります。

public class UserInfo implements Serializable {
    public String mID;
    public String mName;
    public int    mStatus;
}


public class LoginActivity extends Activity {
    private UserInfo mUser;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);

        if (null != savedInstanceState) {
            mUser = savedInstanceState.getSerializable("User");
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putSerializable("User", mUser);
    }
}