読者です 読者をやめる 読者になる 読者になる

kojiko-android’s blog

開発中にハマった時の解決策や、忘れがちなことを残しておきます。

【電卓アプリを作るvol.7】アプリ終了時の状態を保存

前回まで・・・
計算結果に端数が出た場合に、
それを丸めて表示する静的メソッドを実装しました。

今回は、
計算中に電話がかかってきて、
戻ったら全てクリアーされていたという、
悲しいことが起こらないように、
終了時の状態を保存し、
再開したときにロードする機能を実装していきます。

何を保存するべきか

電卓を開いたときに、
どのような情報があれば、
同じ状態を再現できるでしょうか?

最後に見ていたものと、再開直後が違っていたら、
不安になってACを押してしまうでしょう。
なので、
①ディスプレイに表示されている文字列
は欠かせません。
見たままを保存します。
単純に、StringBuilder.toString()で得られる文字列を保存します。

電卓には状態があると前途しました。
状態によって呼び分けられるメソッドが変わってきます。
②現在の状態
を保存します。
現在の状態を知るためのメソッド、
int getStateValue()をすでに用意していますので、
それによって得られた定数も保存します。

状態が右辺入力中なら、
③左辺の情報が無いと計算できません。
演算子も同様です。
定数計算のために、
⑤右辺の値も必要です。

今回はメモリー機能やグランドトータル機能は実装していませんので、
これら5つの情報を保存すれば、
どの状況も再現が可能です。

再現するには

アプリのオンポーズ時にこれらを保存し、
オンレジューム時に、
Calcクラスのインスタンスのフィールドに、
上記の情報を格納します。
stateに状態に応じたクラスのインスタンス
value1に左辺の値をdoubleで、
value2に右辺の値を同じくdouble、
enzanshiは、演算子を示す定数、
stringBuilderに、最後に見ていたのと同じ文字列を入れます。

Calc内に、これら5情報を保持するクラスを作ります

コンストラクターも用意します。

    public class CalcHolder{

        public int state;
        public String dispString;
        public double leftValu,rightValue;
        public int enzanshi;

        public CalcHolder(int state,String dispString, double leftValue,
                          double rightValue, int enzanshi) {

            this.state = state;
            this.dispString = dispString;
            this.leftValu = leftValue;
            this.rightValue = rightValue;
            this.enzanshi = enzanshi;
        }
    }

同じくCalc内に、セーブ用とロード用のパブリックなメソッドを定義します。
セーブ用のgetHolderでは、CalcHolderのインスタンスを返し、
ロード用のsetHolderは、CalcHolderのインスタンスを渡すことによって、
前回の状態に復帰します。

   public CalcHolder getHolder(){
        return new CalcHolder(state.getStateValue(this),stringBuilder.toString(),
                value1,value2,enzanshi);
    }
    
    public void setHolder(CalcHolder holder){
        switch (holder.state){
            case State.STATE_A:
                changeState(StateA.getInstance());
                break;
            case State.STATE_B:
                changeState(StateB.getInstance());
                break;
            case State.STATE_C:
                changeState(StateC.getInstance());
                break;
            case State.STATE_D:
                changeState(StateD.getInstance());
                break;
        }
        this.value1 = holder.leftValu;
        this.value2 = holder.rightValue;
        this.enzanshi = holder.enzanshi;
        set(holder.dispString);
    callback.onTextChanged(stringBuilder.toString());
    }


メインアクティビティのonPauseとonResumeに保存・復帰の処理を記述します。
Gsonを利用しますので、Gsonライブラリーを読み込んで置きます。
(Gsonについての関連記事)

  @Override
    protected void onPause() {
        super.onPause();
        Calc.CalcHolder holder = calc.getHolder();
        Gson gson = new Gson();
        String js = gson.toJson(holder, Calc.CalcHolder.class);
        getSharedPreferences("pref",MODE_PRIVATE).edit().putString("holder",js).apply();
    }

    @Override
    protected void onResume() {
        super.onResume();
        final String NULL = "null";
        Gson gson = new Gson();
        String js = getSharedPreferences("pref",MODE_PRIVATE).getString("holder",NULL);
        if (js.equals(NULL)){
            calc.allClear();
            //    初回起動
        } else {
            calc.setHolder(gson.fromJson(js, Calc.CalcHolder.class));
        }
    }

正しく動作するか確かめてみてください。
マニフェストでアプリをポートレイトにしていなければ、
端末の向きを変えてみて、数字がリセットされないことでも確認できます。

ちなみに、onResume内の「初回起動」とコメントアウトした部分は、
そのまま、ダウンロード後の第一回目の起動なので、
サンキューメッセージ等を表示するのもいいかもしれません。