2017-02-12 6 views
0

Здравствуйте, я работаю над приложением Android-калькулятора в последнее время, и он почти закончен, но теперь он имеет некоторые проблемы, когда числа и другие операторы сбой при нажатии. Затем происходит сбой всего приложения. Листинг кода ниже: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) 

Кажется, я не могу найти, что приводит к сбою программы. Кто-нибудь видит что-нибудь? Я ценю любую помощь!

ответ

0

Удалить эту строку:

CalculatorImpl calc = new CalculatorImpl(this); 

и заменить:

mCalc = new CalculatorImpl(this); 
+0

Спасибо так много! Работал как шарм! Не могли бы вы дать мне краткое объяснение, почему это оригинальное заявление так не сработало? Для будущего уведомления. –

+0

вы создаете новый объект «CalculatorImpl» с именем 'calc' в' onCreate' и используете объект 'mCalc', который не назначен. поэтому он дает ошибку. –

+0

Ох, хорошо. Спасибо! –

Смежные вопросы