Android计算器在点击按钮时崩溃

时间:2017-02-12 02:28:16

标签: java android xml

您好我最近一直在使用Android计算器应用程序,它几乎已经完成,但现在当点击时数字和其他运算符崩溃时会遇到一些问题。然后整个应用程序崩溃。上面的代码如下:

activity_main.xml中

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/calculator_holder"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.stins.calculator.MainActivity">

<TextView
    android:id="@+id/formula"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="2.1"
    android:fontFamily="sans-serif-light"
    android:gravity="right|bottom"
    android:maxLines="1"
    android:paddingLeft="@dimen/activity_margin"
    android:paddingRight="@dimen/activity_margin"
    android:textSize="@dimen/formula_text_size"/>

<TextView
    android:id="@+id/result"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1.8"
    android:fontFamily="sans-serif-light"
    android:gravity="center_vertical|right"
    android:maxLines="1"
    android:paddingLeft="@dimen/activity_margin"
    android:paddingRight="@dimen/activity_margin"
    android:text="0"
    android:textSize="@dimen/display_text_size"/>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="2"
    android:orientation="horizontal">

    <Button
        android:id="@+id/btn_modulo"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="mod"
        android:textAllCaps="false"
        android:textSize="@dimen/mod_text_size"/>

    <Button
        android:id="@+id/btn_power"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="^"/>

    <Button
        android:id="@+id/btn_root"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="√"/>

    <Button
        android:id="@+id/btn_clear"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="C"
        android:longClickable="true"/>

    <Button
        android:id="@+id/btn_reset"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="AC"
        android:visibility="gone"/>
</LinearLayout>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="2"
    android:orientation="horizontal">

    <Button
        android:id="@+id/btn_7"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="7"
        />

    <Button
        android:id="@+id/btn_8"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="8"/>

    <Button
        android:id="@+id/btn_9"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="9"/>

    <Button
        android:id="@+id/btn_divide"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="÷"/>
</LinearLayout>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="2"
    android:orientation="horizontal">

    <Button
        android:id="@+id/btn_4"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="4"/>

    <Button
        android:id="@+id/btn_5"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="5"/>

    <Button
        android:id="@+id/btn_6"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="6"/>

    <Button
        android:id="@+id/btn_multiply"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="*"/>
</LinearLayout>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="2"
    android:orientation="horizontal">

    <Button
        android:id="@+id/btn_1"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="1"/>

    <Button
        android:id="@+id/btn_2"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="2"/>

    <Button
        android:id="@+id/btn_3"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="3"/>

    <Button
        android:id="@+id/btn_minus"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="-"/>
</LinearLayout>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="2"
    android:orientation="horizontal">

    <Button
        android:id="@+id/btn_0"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="0"/>

    <Button
        android:id="@+id/btn_decimal"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="."/>

    <Button
        android:id="@+id/btn_equals"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="="/>

    <Button
        android:id="@+id/btn_plus"
        style="@style/MyButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="+"/>
</LinearLayout>
</LinearLayout>

MainActivity.java

package com.example.stins.calculator;

import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.example.stins.calculator.Calculator;
import com.example.stins.calculator.CalculatorImpl;
import com.example.stins.calculator.Config;
import com.example.stins.calculator.Constants;
import com.example.stins.calculator.Formatter;
import com.example.stins.calculator.Utils;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnLongClick;
import me.grantland.widget.AutofitHelper;

public class MainActivity extends SimpleActivity implements Calculator {
@BindView(R.id.result)
TextView mResult;
@BindView(R.id.formula)
TextView mFormula;

private static CalculatorImpl mCalc;


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

    CalculatorImpl calc = new CalculatorImpl(this);
    AutofitHelper.create(mResult);
    AutofitHelper.create(mFormula);
}

@OnClick(R.id.btn_plus)
public void plusClicked() {
    mCalc.handleOperation(Constants.PLUS);
}

@OnClick(R.id.btn_minus)
public void minusClicked() {
    mCalc.handleOperation(Constants.MINUS);
}

@OnClick(R.id.btn_multiply)
public void multiplyClicked() {
    mCalc.handleOperation(Constants.MULTIPLY);
}

@OnClick(R.id.btn_divide)
public void divideClicked() {
    mCalc.handleOperation(Constants.DIVIDE);
}

@OnClick(R.id.btn_modulo)
public void moduloClicked() {
    mCalc.handleOperation(Constants.MODULO);
}

@OnClick(R.id.btn_power)
public void powerClicked() {
    mCalc.handleOperation(Constants.POWER);
}

@OnClick(R.id.btn_root)
public void rootClicked() {
    mCalc.handleOperation(Constants.ROOT);
}

@OnClick(R.id.btn_clear)
public void clearClicked() {
    mCalc.handleClear();
}

@OnLongClick(R.id.btn_clear)
public boolean clearLongClicked() {
    mCalc.handleReset();
    return true;
}

@OnClick(R.id.btn_equals)
public void equalsClicked() {
    mCalc.handleEquals();
}

@OnClick({R.id.btn_decimal, R.id.btn_0, R.id.btn_1, R.id.btn_2, R.id.btn_3, R.id.btn_4, R.id.btn_5, R.id.btn_6, R.id.btn_7, R.id.btn_8,
        R.id.btn_9})
public void numpadClick(View view) {
    //Toast.makeText(this, "click handler called",  Toast.LENGTH_SHORT).show();
    numpadClicked(view.getId());
}

public void numpadClicked(int id) {
    mCalc.numpadClicked(id);
}


@Override
public void setValue(String value) {
    mResult.setText(value);
}

@Override
public void setValueDouble(double d) {
    mCalc.setValue(Formatter.doubleToString(d));
    mCalc.setLastKey(Constants.DIGIT);
}

public void setFormula(String value) {
    mFormula.setText(value);
}

public CalculatorImpl getCalc() {
    return mCalc;
}
}

CalculatorImpl.java

package com.example.stins.calculator;

public class CalculatorImpl {
private String mDisplayedValue;
private String mDisplayedFormula;
private String mLastKey;
private String mLastOperation;
private Calculator mCallback;

private boolean mIsFirstOperation;
private boolean mResetValue;
private double mBaseValue;
private double mSecondValue;

public CalculatorImpl(Calculator calculator) {
    mCallback = calculator;
    resetValues();
    setValue("0");
    setFormula("");
}

public CalculatorImpl(Calculator calculatorInterface, String value) {
    mCallback = calculatorInterface;
    resetValues();
    mDisplayedValue = value;
    setFormula("");
}

private void resetValueIfNeeded() {
    if (mResetValue)
        mDisplayedValue = "0";

    mResetValue = false;
}

private void resetValues() {
    mBaseValue = 0;
    mSecondValue = 0;
    mResetValue = false;
    mLastKey = "";
    mLastOperation = "";
    mDisplayedValue = "";
    mDisplayedFormula = "";
    mIsFirstOperation = true;
}

public void setValue(String value) {
    mCallback.setValue(value);
    mDisplayedValue = value;
}

private void setFormula(String value) {
    mCallback.setFormula(value);
    mDisplayedFormula = value;
}

private void updateFormula() {
    final String first = Formatter.doubleToString(mBaseValue);
    final String second = Formatter.doubleToString(mSecondValue);
    final String sign = getSign(mLastOperation);

    if (sign.equals("√")) {
        setFormula(sign + first);
    } else if (!sign.isEmpty()) {
        setFormula(first + sign + second);
    }
}

public void setLastKey(String mLastKey) {
    this.mLastKey = mLastKey;
}

public void addDigit(int number) {
    final String currentValue = getDisplayedNumber();
    final String newValue = formatString(currentValue + number);
    setValue(newValue);
}

private String formatString(String str) {
    // if the number contains a decimal, do not try removing the leading zero anymore, nor add group separator
    // it would prevent writing values like 1.02
    if (str.contains("."))
        return str;

    final double doubleValue = Formatter.stringToDouble(str);
    return Formatter.doubleToString(doubleValue);
}

private void updateResult(double value) {
    setValue(Formatter.doubleToString(value));
    mBaseValue = value;
}

public String getDisplayedNumber() {
    return mDisplayedValue;
}

public double getDisplayedNumberAsDouble() {
    return Formatter.stringToDouble(getDisplayedNumber());
}

public String getDisplayedFormula() {
    return mDisplayedFormula;
}

public void handleResult() {
    mSecondValue = getDisplayedNumberAsDouble();
    calculateResult();
    mBaseValue = getDisplayedNumberAsDouble();
}

public void calculateResult() {
    if (!mIsFirstOperation)
        updateFormula();

    switch (mLastOperation) {
        case Constants.PLUS:
            updateResult(mBaseValue + mSecondValue);
            break;
        case Constants.MINUS:
            updateResult(mBaseValue - mSecondValue);
            break;
        case Constants.MULTIPLY:
            updateResult(mBaseValue * mSecondValue);
            break;
        case Constants.DIVIDE:
            divideNumbers();
            break;
        case Constants.MODULO:
            moduloNumbers();
            break;
        case Constants.POWER:
            powerNumbers();
            break;
        case Constants.ROOT:
            updateResult(Math.sqrt(mBaseValue));
            break;
        default:
            break;
    }
    mIsFirstOperation = false;
}

private void divideNumbers() {
    double resultValue = 0;
    if (mSecondValue != 0)
        resultValue = mBaseValue / mSecondValue;

    updateResult(resultValue);
}

private void moduloNumbers() {
    double resultValue = 0;
    if (mSecondValue != 0)
        resultValue = mBaseValue % mSecondValue;

    updateResult(resultValue);
}

private void powerNumbers() {
    double resultValue = Math.pow(mBaseValue, mSecondValue);
    if (Double.isInfinite(resultValue) || Double.isNaN(resultValue))
        resultValue = 0;
    updateResult(resultValue);
}

public void handleOperation(String operation) {
    if (mLastKey.equals(Constants.DIGIT))
        handleResult();

    mResetValue = true;
    mLastKey = operation;
    mLastOperation = operation;

    if (operation.equals(Constants.ROOT))
        calculateResult();
}

public void handleClear() {
    final String oldValue = getDisplayedNumber();
    String newValue = "0";
    final int len = oldValue.length();
    int minLen = 1;
    if (oldValue.contains("-"))
        minLen++;

    if (len > minLen)
        newValue = oldValue.substring(0, len - 1);

    newValue = newValue.replaceAll("\\.$", "");
    newValue = formatString(newValue);
    setValue(newValue);
    mBaseValue = Formatter.stringToDouble(newValue);
}

public void handleReset() {
    resetValues();
    setValue("0");
    setFormula("");
}

public void handleEquals() {
    if (mLastKey.equals(Constants.EQUALS))
        calculateResult();

    if (!mLastKey.equals(Constants.DIGIT))
        return;

    mSecondValue = getDisplayedNumberAsDouble();
    calculateResult();
    mLastKey = Constants.EQUALS;
}

public void decimalClicked() {
    String value = getDisplayedNumber();
    if (!value.contains("."))
        value += ".";
    setValue(value);
}

public void zeroClicked() {
    String value = getDisplayedNumber();
    if (!value.equals("0"))
        addDigit(0);
}

private String getSign(String lastOperation) {
    switch (lastOperation) {
        case Constants.PLUS:
            return "+";
        case Constants.MINUS:
            return "-";
        case Constants.MULTIPLY:
            return "*";
        case Constants.DIVIDE:
            return "/";
        case Constants.MODULO:
            return "%";
        case Constants.POWER:
            return "^";
        case Constants.ROOT:
            return "√";
    }
    return "";
}

public void numpadClicked(int id) {
    if (mLastKey.equals(Constants.EQUALS))
        mLastOperation = Constants.EQUALS;
    mLastKey = Constants.DIGIT;
    resetValueIfNeeded();

    switch (id) {
        case R.id.btn_decimal:
            decimalClicked();
            break;
        case R.id.btn_0:
            zeroClicked();
            break;
        case R.id.btn_1:
            addDigit(1);
            break;
        case R.id.btn_2:
            addDigit(2);
            break;
        case R.id.btn_3:
            addDigit(3);
            break;
        case R.id.btn_4:
            addDigit(4);
            break;
        case R.id.btn_5:
            addDigit(5);
            break;
        case R.id.btn_6:
            addDigit(6);
            break;
        case R.id.btn_7:
            addDigit(7);
            break;
        case R.id.btn_8:
            addDigit(8);
            break;
        case R.id.btn_9:
            addDigit(9);
            break;
        default:
            break;
    }
}
}

logcat的

02-11 20:18:59.116 6438-6438/com.example.stins.calculator E/AndroidRuntime: FATAL EXCEPTION: main
                                                                            Process: com.example.stins.calculator, PID: 6438
                                                                            java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.stins.calculator.CalculatorImpl.numpadClicked(int)' on a null object reference
                                                                                at com.example.stins.calculator.MainActivity.numpadClicked(MainActivity.java:105)
                                                                                at com.example.stins.calculator.MainActivity.numpadClick(MainActivity.java:101)
                                                                                at com.example.stins.calculator.MainActivity_ViewBinding$16.doClick(MainActivity_ViewBinding.java:192)
                                                                                at butterknife.internal.DebouncingOnClickListener.onClick(DebouncingOnClickListener.java:22)
                                                                                at android.view.View.performClick(View.java:5198)
                                                                                at android.view.View$PerformClick.run(View.java:21147)
                                                                                at android.os.Handler.handleCallback(Handler.java:739)
                                                                                at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                                at android.os.Looper.loop(Looper.java:148)
                                                                                at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                                at java.lang.reflect.Method.invoke(Native Method)
                                                                                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

我似乎无法找到导致程序崩溃的原因。有谁看到了什么?我感谢任何和所有的帮助!

1 个答案:

答案 0 :(得分:0)

删除此行:

CalculatorImpl calc = new CalculatorImpl(this);

并替换为:

mCalc = new CalculatorImpl(this);