アプリ開発初心者の暇つぶしAndroid体験記

アプリ開発初心者がAndroidアプリ開発始めました。日々学んだことをアウトプットしていきます。

電卓を作ろう【デバッグ編】

今回は色々と動かして気になったところを直しました!
Android Studioを使ったデバッグ方法を紹介します!

修正ソースを載せようか迷いましたが、細かすぎるのでやめました。汗
それではやっていきます!

1. デバッグモードでのアプリ起動

まずはアプリをデバッグモードで起動します。
ツールバーの[実行] -> [デバッグ] を選択することで
アプリがデバッグモードで起動します。

2. ブレークポイントの設定

デバッグモードで動作しているアプリを、処理の途中で止めるためにブレークポイントなるものを設定します。
止めたいコードの枠外(行数表示の右)をクリックすると赤い丸が表示されます。
これがブレークポイントです。
f:id:mtnanao:20200226231354p:plain

3. デバッグ作業

それでは、ブレークポイントを通過するようにアプリを動かしてみましょう!
すると、このようにブレークポイントの位置でアプリが停止します。
f:id:mtnanao:20200226231849p:plain

右下に変数ウィンドウが表示されており、
止まった時点での各変数に格納されている値を見ることができます。

とまった位置からアプリを1行ずつ(ステップ実行)することもできます。
良く使うのは「ステップオーバー」(F8キー)でしょうか。
階層は変えず、そのまま次の行に進みます。こんな感じですね。
f:id:mtnanao:20200226232350p:plain

他にも、階層を1つ下る「ステップイン」や、
階層を1つ上る「ステップアウト」などもあります。

また、F9キーを押すことで次のブレークポイントにぶつかるまで処理をとばすことができます。
ブレークポイントを複数おいて、ポイントポイントで動きを確認したい時はF9キーで進んだほうが効率的ですね!


それでは今回はここまでとします!
お疲れさまでした!!

電卓を作ろう【クリア処理実装編】

今回はクリア処理の実装を行っていきます!

メインの計算処理は前回の記事をご覧ください!
それではやっていきましょう!

1. Cボタンの実装

今回の電卓ではCボタンは末尾の一文字を消す処理とします。
大きく、演算記号を消した時と数字を消した時で動きが変わります。
では、実装を見ていきます!

case R.id.clear:
    if (calc.getText().toString().endsWith("+") ||
        calc.getText().toString().endsWith("-") ||
        calc.getText().toString().endsWith("*") ||
        calc.getText().toString().endsWith("/") ) {
        
        // 演算記号を消す場合
        calcList.remove(calcList.size() -1 );
        tmpCalcNum = "";

    } else {

        // 演算記号以外を消す場合
        tmpCalcNum = tmpCalcNum.substring(0,tmpCalcNum.length() - 1);

    }

    // 表示文字列の最後の文字を削除する
    viewNum = calc.getText().toString().substring(0,calc.getText().toString().length()-1);
    calc.setText(viewNum);

    break;

演算記号を削除する場合、計算用に作っているcalcListの最後の要素にはこの演算記号が入っています。

演算記号が入っている要素をList#removeを使って削除します。
List#removeの引数には削除する要素を番号で指定します。
最初の要素は0、最後の要素はリストサイズ -1 になるので、今回はcalcList.size() - 1ですね。

演算記号以外を削除する場合は、tmpCalcNumの末尾を削除します。
tmpCalcNumには直近の演算項が入っています。(詳細は計算処理実装編)

2. CAボタンの実装

CAはすべて初期化する処理とするため、そこまで複雑ではないですね!

case R.id.clearall:
    // 表示文字の初期化
    calc.setText("");
    // 演算モードの初期化
    calcMode = "";
    // 計算用リストの初期化
    calcList.clear();
    // 直近の演算項を初期化
    tmpCalcNum = "";
    break;

処理に出てくる変数を順々に初期化しています。

3. 演算ボタンの修正

以下のような流れでボタンが押されたことを考慮して、
演算ボタンを少しだけ直しておきます。

  1. 「10+6+」の状態でCボタンが押される
    • tmpCalcNumには""が設定されている
  2. 「10+6」の状態で-ボタンが押される
    • tmpCalcNumには""が設定されたまま、calcListにaddされてしまう(←想定外の動き)

なので、各演算ボタンに1つだけ分岐を設けます。

case R.id.plus:
    if (!tmpCalcNum.equals("")) {
        calcList.add(tmpCalcNum);
    }
    calcList.add("+");

    viewNum = calc.getText().toString() + "+";
    calc.setText(viewNum);

    tmpCalcNum = "";

    break;

tmpCalcNumが""である場合は、calcListへのaddを行いません。

4. 動作確認

画像では伝わりにくいですが動かしてみます!
f:id:mtnanao:20200224185745p:plain

この状態でCボタンを押すと、、、
f:id:mtnanao:20200224185756p:plain
末尾の数字が消えました!

次にCAボタンを押してみます。
f:id:mtnanao:20200224185805p:plain
すべて削除されました!

Cボタン、CAボタンを押した後の計算結果も問題なかったです。


それでは今回はここまでです!
お疲れさまでした!!

電卓を作ろう【計算処理実装編】

今回は計算処理の実装です!
Listやfor文を駆使して実現させます!

やっとここまで来ました!
それではやっていきます。

1. 数字・小数点ボタン処理実装

まずは数字と小数点のボタン処理にコードを追加していきます。
例として"1"が押された時のコードを載せておきます。

// 1が押された場合の処理
case R.id.one:

    viewNum = calc.getText().toString() + "1";
    calc.setText(viewNum);

    tmpCalcNum += "1";

    break;

追加したのは以下の1行です。

tmpCalcNum += "1";

変数tmpCalcNumは文字列型で宣言してあり、直前の演算記号以降に押された数字を保持します。
例えば 「10+5+30」 の場合は、
変数tmpCalcNumには"30"が入っていることになります。

2. 演算記号ボタン処理実装

次に演算記号が押された場合の処理です。
例として"+"が押された場合の処理が以下です。

// +が押された場合の処理
case R.id.plus:

    // calcListに計算する情報を追加する。(数字と演算記号)
    calcList.add(tmpCalcNum);
    calcList.add("+");
    tmpCalcNum = "";

    viewNum = calc.getText().toString() + "+";
    calc.setText(viewNum);

    break;

calcListは文字列型のリストで宣言しています。
このリストにList#addを使い、変数tmpCalcNumと文字列"+"を追加します。
先ほどの例をもう一度使うと、
 「10+5+30」
この状態で"+"を押すと、"30"と"+"がcalcListに追加されるというわけです。
そして演算記号が押されたことによりtmpCalcNumは初期化する必要があるため、空文字を設定します。
残りの"-"、"*"、"/"のボタンも同じように実装します。

3. "="ボタン処理実装

最後は、"="を押した時です。
このタイミングでcalcListに入っている数字と演算記号を順々に読んで計算していきます。

// =が押された場合の処理
case R.id.eq:

    // 直前の数字をcalcListに追加する
    calcList.add(tmpCalcNum);

    for (String calc : calcList) {

        // 演算記号の場合は、計算モードを設定する
        if (calc.equals("+")) {
            calcMode = "pl";
        } else if (calc.equals("-")) {
            calcMode = "mi";
        } else if (calc.equals("*")) {
            calcMode = "mu";
        } else if (calc.equals("/")) {
            calcMode = "di";
        } else {
            // 演算記号以外(数字)の場合は、計算モードを元に計算する
            if (calcMode.equals("pl")) {
                resultNum += Double.parseDouble(calc);
            } else if (calcMode.equals("mi")) {
                resultNum -= Double.parseDouble(calc);
            } else if (calcMode.equals("mu")) {
                resultNum *= Double.parseDouble(calc);
            } else if (calcMode.equals("di")) {
                resultNum /= Double.parseDouble(calc);
            } else {
                // 計算モードがどれでもない場合は、最初の数字なのでresultNumに設定
                resultNum = Double.parseDouble(calc);
            }
        }
    }

    calc.setText(resultNum.toString());

    calcMode = "";
    tmpCalcNum = "";

    calcList.clear();
    tmpCalcNum = resultNum.toString();

    break;

calcListをfor文で回していきます。
要素が演算記号の場合は、計算モードを指定します。
要素が演算記号でない場合(つまり数字の場合)は、計算モードに基づき計算を行います。
順々に計算していき、全要素を読み込んだあとは結果をTextViewに表示します。
結果を使って続けて電卓を打つことがあるので、最後に必要な変数を初期化します。

4. 動作確認

それでは動かしてみます!
f:id:mtnanao:20200222220127p:plain
f:id:mtnanao:20200222220137p:plain

正しく計算されていますね!

(掛け算と割り算を最初に計算するように作られてないのは内緒。笑)
(あと整数しか入れてないのに結果が少数点表記なのは気になる・・・)


本日はここまでです!
お疲れ様でした!!

電卓を作ろう【表示処理実装編】

今回は各ボタンが押された時にTextViewに表示させる処理を実装していきます!

完成まで長そうです。笑
では、やっていきましょう!

1. イベントリスナーの追加

配置したすべてのボタンにイベントリスナーを追加していきます。
イベントリスナーについてはこちらも参考にどうぞ。
xprogrammingx.hatenablog.com

実装したonCreateメソッドがこちらです。

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

    // 2020.02.24 電卓の計算処理実装
    findViewById(R.id.one).setOnClickListener(this);
    findViewById(R.id.two).setOnClickListener(this);
    findViewById(R.id.three).setOnClickListener(this);
    findViewById(R.id.four).setOnClickListener(this);
    findViewById(R.id.five).setOnClickListener(this);
    findViewById(R.id.six).setOnClickListener(this);
    findViewById(R.id.seven).setOnClickListener(this);
    findViewById(R.id.eight).setOnClickListener(this);
    findViewById(R.id.nine).setOnClickListener(this);
    findViewById(R.id.zero).setOnClickListener(this);
    findViewById(R.id.period).setOnClickListener(this);
    findViewById(R.id.plus).setOnClickListener(this);
    findViewById(R.id.minus).setOnClickListener(this);
    findViewById(R.id.multi).setOnClickListener(this);
    findViewById(R.id.div).setOnClickListener(this);
    findViewById(R.id.eq).setOnClickListener(this);
    findViewById(R.id.clear).setOnClickListener(this);
    findViewById(R.id.clearall).setOnClickListener(this);

    calc = findViewById(R.id.calc);
}

ボタンが多いとこれだけで一苦労ですね。笑
足りてるよね・・・?

2. onClickメソッドの実装

onClickメソッドを追加し、switch文を追加。
過去に触れているのでここでの解説は省略します。
xprogrammingx.hatenablog.com


各ボタンが押された場合の処理を実装していきます。
処理の流れはこんな感じでしょうか!

  1. TextViewの文字列を取得
  2. 押された文字を末尾に追加
  3. 再度TextViewに表示

例として、"1"が押された場合の処理がこちらです!

// 1が押された場合の処理
case R.id.one:
    viewNum = calc.getText().toString() + "1";
    calc.setText(viewNum);
    break;

これを各ボタンが押された場合の処理にも追加していきます。

3. 動作確認

それでは、正しく表示されるか確認してみます!
f:id:mtnanao:20200222203721p:plain

各数字と演算記号が表示されてますね!




それでは、今回はここまでとします!
次回はいよいよ電卓のメイン、計算処理です!

お疲れさまでした!

電卓を作ろう【レイアウト作成編】

本日から電卓を作っていきます!
今回はレイアウト編ということで画面を作っていきます!

新しいプロジェクトを作って0から開始します!

1. TableLayoutでボタン配置

電卓のボタン配置にはTableLayoutを使っていきます。
Tableの名の通り、マス目のようにレイアウトを作っていけます。
とりあえずボタンだけ配置したのがこちら!
f:id:mtnanao:20200222143542p:plain

ここから見た目を調整していきましょう!

2. レイアウトの調整

まずは、1段目のボタンを右に寄せたいです。
layout_columnという属性で、左からの何列目に配置するかを指定できるようです。

<Button
    android:id="@+id/clear"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_column="2"
    android:text="C" />

<Button
    android:id="@+id/clearall"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_column="3"
    android:text="CA" />

1列目を0として、1つずつ増えていきます。
なので、"C"には layout_columnに2を設定し、"AC"にはlayout_columnに3を設定します。

次に画面右側に余白が出来てしまっているので、幅を調整します。
layout_widthに0dpを設定し、layout_weightに1を設定することで
画面の幅いっぱいにボタン幅が調整できます。

<Button
    android:id="@+id/clear"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="wrap_content"
    android:layout_column="2"
    android:text="C" />

<Button
    android:id="@+id/clearall"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="wrap_content"
    android:layout_column="3"
    android:text="CA" />

これを全部のボタンに設定します。
f:id:mtnanao:20200222152155p:plain

すると、あれ1段目のボタン幅が広がってる・・・。
どうにもならないので、空文字のTextViewを突っ込んでむりやり揃えました。
もっといい方法がありそう・・・。
(これによりlayout_columnも指定の必要がなくなりました汗)

<TextView
    android:id="@+id/dummy"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="wrap_content"
    android:text="" />

<TextView
    android:id="@+id/dummy2"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="wrap_content"
    android:text="" />

<Button
    android:id="@+id/clear"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="wrap_content"
    android:layout_column="2"
    android:text="C" />

<Button
    android:id="@+id/clearall"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="wrap_content"
    android:layout_column="3"
    android:text="CA" />

f:id:mtnanao:20200222153250p:plain

3. 表示エリアを配置

ボタンの上に数字の表示エリアを定義してます。
今回は右寄せで表示するようにgravityにrightを指定します。

<TextView
    android:id="@+id/calc"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="right"
    android:textSize="60sp" />

4. 動作確認

レイアウトのみですが、エミュレーターで確認しておきましょう!
f:id:mtnanao:20200222155030p:plain:w250
f:id:mtnanao:20200222155132p:plain:h250

画面サイズに合わせるように作ったので横向きでも
綺麗に並んでいます!


本日はここまでです!次回は処理を実装していきます!
お疲れさまでした!

電卓を作ろう【序章】

やっとアプリ開発らしくなってきました。笑
今回は電卓を作り始める前に、前回までの不具合を解消しておきたいと思います!


改善点は2つ

  1. 小数点以下の桁に対応する
  2. 割る数に0が入っても落ちないようにする

それではやっていきます!

1. 浮動小数点型を使う

修正前は以下の通り、結果をLong型に格納していました。

Long resultPlus = number1 + number2;
result.setText(number1 + "+" + number2 + "=" + resultPlus.toString());

Long型では整数しか扱えないので、double型に変えていきます。
修正後のソースがこちら!

@Override
public void onClick(View v) {

    // 2020.02.23 小数点対応のため修正
    double number1 = Double.parseDouble(editNum1.getText().toString());
    double number2 = Double.parseDouble(editNum2.getText().toString());
    String text = "";

    switch (v.getId()){

        case R.id.plus:

            // 足し算処理
            // 2020.02.23 小数点対応のため修正
            double resultPlus = number1 + number2;
            text = number1 + "+" + number2 + "=" + resultPlus;
            break;

        case R.id.minus:

            // 引き算処理
            // 2020.02.23 小数点対応のため修正
            double resultMinus = number1 - number2;
            text = number1 + "-" + number2 + "=" + resultMinus;
            break;

        case R.id.multi:

            // 掛け算処理
            // 2020.02.23 小数点対応のため修正
            double resultMulti = number1 * number2;
            text = number1 + "×" + number2 + "=" + resultMulti;
            break;

        case R.id.div:

            // 割り算処理
            // 2020.02.23 小数点対応のため修正
            double resultDiv = number1 / number2;
            text = number1 + "÷" + number2 + "=" + resultDiv;
            break;

    }
    result.setText(text);
}

実行結果は後程確認します!

2. 0が入力された場合の処理を実装

続いてNumber2に0を入れて割り算を実行すると
アプリが落ちてしまう現象です。
今回double型に変えたことによりArithmeticExceptionは
発生しなくなりました。

f:id:mtnanao:20200222115216p:plain:w200

このように計算結果がInfinityとなっています。
例外は発生しないため、try-catchではなくif文で分岐させていきます。

case R.id.div:
    if (number2 == 0) {
        text = "エラー";
    } else {
        Double resultDiv = number1 / number2;
        text = number1 + "÷" + number2 + "=" + resultDiv;
    }
    break;

これでNumber2に0が入った場合はエラーと表示されるでしょう!

3. 動作確認

それでは動かしていきましょう!

f:id:mtnanao:20200222123403p:plain:w200
f:id:mtnanao:20200222123420p:plain:w200
f:id:mtnanao:20200222123432p:plain:w200
f:id:mtnanao:20200222123445p:plain:w200
f:id:mtnanao:20200222123456p:plain:w200

四則演算の少数対応と、0で割ったときのエラー表示が出来ました。


それでは今回はここまでです!
次回は電卓のレイアウトを作っていきます!

お疲れさまでした!!

複数のボタンからの処理を実装してみる

今回は、1画面に複数ボタンがある場合の処理について勉強したいと思います。

目標は、四則演算です!

 

 

前回まで作っていたアプリに改造を加えていきます!

それでは、やってみます!

 

1. レイアウト作成

四則演算するため、ボタンを追加します!

ボタンは横に4つ並べることとします。

LinearLayoutで定義しました。

f:id:mtnanao:20200219210010p:plain

うーん、ボタンの大きさがちょっと違う・・?

 

LinearLayoutでは横一列に並んだボタンの比率を指定できるようなので試してみます。

f:id:mtnanao:20200219210639p:plain

きれいに揃いました!

4つすべてのボタンのlayout_weightに1を指定しました。

これによって4つのボタンが1:1:1:1になることが分かりましたね!

 

2. イベントリスナーを追加

ボタンがクリックされた時に反応するよう、各ボタンにイベントリスナーを追加していきます。

イベントリスナーについては以前触れているので、そちらもご覧ください。

xprogrammingx.hatenablog.com

 

 では、イベントリスナー追加後の実装がこちらです!

f:id:mtnanao:20200219211832p:plain

29行目、32行目、35行目、38行目でそれぞれのボタンにイベントリスナーを追加しています。

 

3. 計算処理の実装

次はonClickメソッドに計算処理の実装です。

メソッド名はonClickで固定なので、ボタンごとにメソッドを作成することは出来ないですね。

複数ボタンがある場合は、onClickメソッドの引数であるViewクラスの変数vを使うとうまくいくみたいです!

ViewクラスにはgetId()メソッドが用意されており、idを確認することによってどのボタンからonClickメソッドが呼ばれたかが判断できるようです。

では、idによる分岐処理を実装していきます。

f:id:mtnanao:20200219213838p:plain

追加した部分は以下の通りです。

  1. [66行目] onClickの引数vのView#getIdを実行し、結果によってcase文で分岐させます。
  2. [68行目] View#getIdの結果がR.id.plusの場合の処理を記述します。中身は前回までのを流用。
  3. [79行目] View#getIdの結果がR.id.minusの場合の処理を記述します。
  4. [83行目] View#getIdの結果がR.id.multiの場合の処理を記述します。
  5. [87行目] View#getIdの結果がR.id.divの場合の処理を記述します。

 

onClickの引数vがnullになることはあるのでしょうか。

nullかどうかの確認は今回入れてませんが、引数vがnullだと例外が発生してしまいます。

 

それぞれの計算処理を実装して実行してみましょう!

f:id:mtnanao:20200219221244p:plain

f:id:mtnanao:20200219221259p:plain

 

4. 動作確認

それぞれ計算してみました!

Long型に結果を格納しているので、少数点以下の桁に対応が出来ていませんでした。汗

f:id:mtnanao:20200219221328p:plain

f:id:mtnanao:20200219221338p:plain

f:id:mtnanao:20200219221348p:plain

f:id:mtnanao:20200219221404p:plain


あと、Number2に0を入れると・・・・

f:id:mtnanao:20200219222139p:plain

0では割り算できないのでエラーになります。

電卓とか作る場合は、0で割られることを考慮して実装が必要ですね。

 

とりあえず四則演算は出来たので今回はここまでとします!

お疲れさまでした!!