6

I am trying to create a calculator design.But I do not get any compile time errors.Finally while running the Project/code a nullpointer exception Error occured.

MainActivity.java:

public class MainActivity extends Activity {
GridView mKeypadGrid;
KeyAdapter mKeypadAdapter;
private TextView userInputText;
private boolean resetInput;
private boolean hasFinalResult;
private String mDecimalSeperator;
private Stack<String> mInputStack;
private Stack<String> mOperationStack;
private double memoryValue;
private TextView mStackText;
private TextView memoryStatText;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

 userInputText= (TextView) findViewById(R.id.txtInput); 
 mStackText=(TextView)findViewById(R.id.txtStack);
 memoryStatText=(TextView)findViewById(R.id.txtMemory);
 mKeypadGrid = (GridView)findViewById(R.id.grdButtons);

 mKeypadAdapter = new KeyAdapter(this);


 mKeypadGrid.setAdapter(mKeypadAdapter);
 mKeypadAdapter.setOnButtonClickListener(new OnClickListener() {
     @Override
     public void onClick(View v) {
       Button btn = (Button) v;

       KeypadButton keypadButton = (KeypadButton) btn.getTag();


       ProcessKeypadInput(keypadButton);
      }});
 mKeypadGrid.setOnItemClickListener(new OnItemClickListener() {
     public void onItemClick(AdapterView<?> parent, View v,int position, long id) {

     }
 });
}

 public void ProcessKeypadInput(KeypadButton keypadButton) {

        String text = keypadButton.getText().toString();
        String currentInput = userInputText.getText().toString();

        int currentInputLen = currentInput.length();
        String evalResult = null;
        double userInputValue = Double.NaN;

        switch (keypadButton) {
        case BACKSPACE: 
            if (resetInput)
                return;

            int endIndex = currentInputLen - 1;


            if (endIndex < 1) {
                userInputText.setText("0");
            }
            else {
                userInputText.setText(currentInput.subSequence(0, endIndex));
            }
            break;
        case SIGN:  
            if (currentInputLen > 0 && currentInput != "0") {

                if (currentInput.charAt(0) == '-') {
                    userInputText.setText(currentInput.subSequence(1,
                            currentInputLen));
                }

                else {
                    userInputText.setText("-" + currentInput.toString());
                }
            }
            break;
        case CE: 
            userInputText.setText("0");
            break;
        case C:
            userInputText.setText("0");
            clearStacks();
            break;
        case DECIMAL_SEP: 
            if (hasFinalResult || resetInput) {
                userInputText.setText("0" + mDecimalSeperator);
                hasFinalResult = false;
                resetInput = false;
            } else if (currentInput.contains("."))
                return;
            else
                userInputText.append(mDecimalSeperator);
            break;
        case DIV:
        case PLUS:
        case MINUS:
            case MULTIPLY:
            if (resetInput) {
                mInputStack.pop();
                mOperationStack.pop();
            } else {
                if (currentInputLen >0) {
                    if (currentInput.charAt(0) == '-') {

                } else {
                    if(currentInput!=null)
                    mInputStack.add(currentInput);
                }
                mOperationStack.add(currentInput);
            }
            }
            if(text!=null){
            mInputStack.add(text); //132nd Line
            mOperationStack.add(text);
            }
            dumpInputStack();
            evalResult = evaluateResult(false);
            if (evalResult != null)
                userInputText.setText(evalResult);

            resetInput = true;
            break;
        case CALCULATE:
            if (mOperationStack.size() == 0)
                break;

            mOperationStack.add(currentInput);
            evalResult = evaluateResult(true);
            if (evalResult != null) {
                clearStacks();
                userInputText.setText(evalResult);
                resetInput = false;
                hasFinalResult = true;
            }
            break;
        case M_ADD: 
            userInputValue = tryParseUserInput();
            if (Double.isNaN(userInputValue))
                return;
            if (Double.isNaN(memoryValue))
                memoryValue = 0;
            memoryValue += userInputValue;
            displayMemoryStat();

            hasFinalResult = true;

            break;
        case M_REMOVE: 
            userInputValue = tryParseUserInput();
            if (Double.isNaN(userInputValue))
                return;
            if (Double.isNaN(memoryValue))
                memoryValue = 0;
            memoryValue -= userInputValue;
            displayMemoryStat();
            hasFinalResult = true;
            break;
        case MC: 
            memoryValue = Double.NaN;
            displayMemoryStat();
            break;
        case MR:
            if (Double.isNaN(memoryValue))
                return;
            userInputText.setText(doubleToString(memoryValue));
            displayMemoryStat();
            break;
        case MS:
            userInputValue = tryParseUserInput();
            if (Double.isNaN(userInputValue))
                return;
            memoryValue = userInputValue;
            displayMemoryStat();
            hasFinalResult = true;
            break;
        default:
            if (Character.isDigit(text.charAt(0))) {
                if (currentInput.equals("0") || resetInput || hasFinalResult) {
                    userInputText.setText(text);
                    resetInput = false;
                    hasFinalResult = false;
                } else {
                    userInputText.append(text);
                    resetInput = false;
                }

            }
            break;

        }

    }

    public void clearStacks() {
        mInputStack.clear();
        mOperationStack.clear();
        mStackText.setText("");
    }

    public void dumpInputStack() {
        Iterator<String> it = mInputStack.iterator();
        StringBuilder sb = new StringBuilder();

        while (it.hasNext()) {
            CharSequence iValue = it.next();
            sb.append(iValue);

        }

        mStackText.setText(sb.toString());
    }

    public String evaluateResult(boolean requestedByUser) {
        if ((!requestedByUser && mOperationStack.size() != 4)
                || (requestedByUser && mOperationStack.size() != 3))
            return null;

        String left = (String) mOperationStack.get(0);
        String operator = (String) mOperationStack.get(1);
        String right = (String) mOperationStack.get(2);
        String tmp = null;
        if (!requestedByUser)
            tmp = (String) mOperationStack.get(3);

        double leftVal = Double.parseDouble(left.toString());
        double rightVal = Double.parseDouble(right.toString());
        double result = Double.NaN;

        if (operator.equals(KeypadButton.DIV.getText())) {
            result = leftVal / rightVal;
        } else if (operator.equals(KeypadButton.MULTIPLY.getText())) {
            result = leftVal * rightVal;

        } else if (operator.equals(KeypadButton.PLUS.getText())) {
            result = leftVal + rightVal;
        } else if (operator.equals(KeypadButton.MINUS.getText())) {
            result = leftVal - rightVal;

        }

        String resultStr = doubleToString(result);
        if (resultStr == null)
            return null;

        mOperationStack.clear();
        if (!requestedByUser) {
            mOperationStack.add(resultStr);
            mOperationStack.add(tmp);
        }

        return resultStr;
    }

    public String doubleToString(double value) {
        if (Double.isNaN(value))
            return null;

        long longVal = (long) value;
        if (longVal == value)
            return Long.toString(longVal);
        else
            return Double.toString(value);

    }

    public double tryParseUserInput() {
        String inputStr = userInputText.getText().toString();
        double result = Double.NaN;
        try {
            result = Double.parseDouble(inputStr);

        } catch (NumberFormatException nfe) {}
        return result;

    }

    public void displayMemoryStat() {
        if (Double.isNaN(memoryValue)) {
            memoryStatText.setText("");
        } else {
            memoryStatText.setText("M = " + doubleToString(memoryValue));
        }
    }
 }

activity_main.xml:

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <TextView  
        android:id="@+id/txtStack"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:textSize="15sp"
        android:gravity="right"
        android:layout_marginTop = "3sp"
        android:layout_marginLeft = "5sp"
        android:layout_marginRight = "5sp"/>


    <TextView  
        android:id="@+id/txtInput"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:textSize="25sp"
        android:gravity="right"
        android:layout_marginLeft = "5sp"
        android:layout_marginRight = "5sp"/>


    <TextView  
        android:id="@+id/txtMemory"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:textSize="15sp"
        android:gravity="left"
        android:layout_marginLeft = "5sp"
        android:layout_marginRight = "5sp"/>

<GridView 
    android:id="@+id/grdButtons"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:columnWidth="90dp"
    android:numColumns="5"
    android:verticalSpacing="10dp"
    android:horizontalSpacing="10dp"
    android:stretchMode="columnWidth"
    android:gravity="center"/>
</LinearLayout>

Output:

image

Stack Trace:

 E/AndroidRuntime(1492): FATAL EXCEPTION: main
 E/AndroidRuntime(1492): Process: com.calculator, PID: 1492
 E/AndroidRuntime(1492): java.lang.NullPointerException
 E/AndroidRuntime(1492): at com.calculator.MainActivity.ProcessKeypadInput(MainActivity.java:132)
 E/AndroidRuntime(1492): at com.calculator.MainActivity$1.onClick(MainActivity.java:50)
 E/AndroidRuntime(1492): at android.view.View.performClick(View.java:4438)
 E/AndroidRuntime(1492): at android.view.View$PerformClick.run(View.java:18422)
 E/AndroidRuntime(1492): at android.os.Handler.handleCallback(Handler.java:733)
 E/AndroidRuntime(1492): at android.os.Handler.dispatchMessage(Handler.java:95)
 E/AndroidRuntime(1492): at android.os.Looper.loop(Looper.java:136)
 E/AndroidRuntime(1492): at android.app.ActivityThread.main(ActivityThread.java:5017)
 E/AndroidRuntime(1492): at java.lang.reflect.Method.invokeNative(Native Method)
 E/AndroidRuntime(1492): at java.lang.reflect.Method.invoke(Method.java:515)
 E/AndroidRuntime(1492): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
 E/AndroidRuntime(1492): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
 E/AndroidRuntime(1492): at dalvik.system.NativeStart.main(Native Method)
  • I do not know how to fix the NullPointer Exception Error.

  • Problem is while pressing the
    +(plus),-(minus),*(mul),/(div),MC,MR,C,=(equal) and Comma Buttons Logcat Error occured.Other buttons like 0,1,2,3 to 9 its fine.

  • Your answer will be most welcome here.

  • Thank you

Shayden117
  • 252
  • 1
  • 3
  • 17

2 Answers2

4

In onCreate, need to add findViewById for userInputText

userInputText= (TextView) findViewById(R.id.txtInput);  

Likewise for other layout components, else no identification for getText()

And when you do that, please do not use the same TextView from code for all components...

userInputText= (TextView) findViewById(R.id.txtInput); 
userInputText=(TextView)findViewById(R.id.txtStack);
userInputText=(TextView)findViewById(R.id.txtMemory);

is incorrect.

Use different TextView for stack and memory.... like stackInputText, memoryInputText

Pararth
  • 8,114
  • 4
  • 34
  • 51
  • I do that.now I got a Output.But I get a error while pressing the +(plus),-(minus),*(mul),/(div),MC,MR,C,=(equal) and Comma Buttons. –  Feb 13 '14 at 06:00
  • I added TextView to txtInput,txtStack and txtMemory.But I got calculator output.Problem is while pressing the +(plus),-(minus),*(mul),/(div),MC,MR,C,=(equal) and Comma Buttons Logcat Error occured.Other buttons like 0,1,2,3 to 9 its fine. –  Feb 13 '14 at 06:09
  • 1
    Is there any way to get a output –  Feb 13 '14 at 06:30
  • is logcat giving you the same error after initializing all textviews separately? – Pararth Feb 13 '14 at 06:35
  • 1
    Now logcat error doesnt occur.But If I press +(plus) button, Calculator unfortunately stopped Alert dialog box appears. then suddently it closes the emulator. –  Feb 13 '14 at 06:40
  • so when your app crashes, your logcat will read the exception/error, post that – Pararth Feb 13 '14 at 06:42
  • check it.I post the new logcat image –  Feb 13 '14 at 06:47
  • U check that logcat image. –  Feb 13 '14 at 07:01
  • yes, but its not from at the time of the crash, scroll up or see where you can find the error/exception posts – Pararth Feb 13 '14 at 07:03
  • 2
    I find and post the Logcat image :) –  Feb 13 '14 at 08:05
  • 1
    can you able to check it and tell me –  Feb 13 '14 at 08:16
  • Sorry to butt in. Is the exception still stringindexoutofbounds? – lorraine batol Feb 13 '14 at 08:19
  • What code is at line 121? Seems some array isnt populated but x pos is being requested – Pararth Feb 13 '14 at 08:22
2

Under your ProcessKeypadInput method, you have the following code:

case MULTIPLY:
        if (resetInput) {
            mInputStack.pop();
            mOperationStack.pop();
        } else {
            if (currentInput.charAt(0) == '-') {     // <-------- Problem line
                mInputStack.add("(" + currentInput + ")");
            } else {
                mInputStack.add(currentInput);
            }
            mOperationStack.add(currentInput);
        }

I indicated which line appears to be causing the issue you are seeing in logcat. You are attempting to evaluate the first character of currentInput but have nothing that will ensure currentInput contains any characters. If you try to evaluate the first character of a string which has no characters at all, it would throw the exception you are seeing.

One solution would be to change the line in question and below to the following:

...
    if (currentInputLen > 0) {
        if (currentInput.charAt(0) == '-') {
            mInputStack.add("(" + currentInput + ")");
        } else {
            mInputStack.add(currentInput);
        }
        mOperationStack.add(currentInput);
    }
}

This would prevent that attempt to evaluate the first character unless the string contained at least one character, and also prevent null pointer exceptions.

mike47
  • 2,217
  • 1
  • 27
  • 50
  • 1
    Then the value of `text` is null. You need to insert appropriate checks throughout your code to check for null or invalid values before performing operations with them. There are several ways to do this, depending on the type of variable and what you are doing. I used the example of checking the string length because you had already defined a variable with string length. You can also use a statement like (mySomething != null) or mySomething.isEmpty(). I avoid the isEmpty() method because it requires API 9 or newer, while the other methods work across all Android versions. – mike47 Feb 28 '14 at 08:56
  • The drawback with using features from newer APIs is that it limits what users can install your app. If you have no intentions of supporting API <9, you can use isEmpty() if that is what you prefer. – mike47 Feb 28 '14 at 09:04
  • Where I have to include that method –  Feb 28 '14 at 09:06
  • Use any of the methods I mentioned wherever you need to check for a valid value. If you are getting null pointer errors for a value on line 130, then determine what value is causing the problem (`text` in that case), and use an if statement to only execute that line if it is not null. For example, `if (text != null) ...` – mike47 Feb 28 '14 at 09:13
  • What you told that I changed the method.Check it.But still error remains same –  Feb 28 '14 at 09:33
  • The code now shown in your question does not match what I suggested in my answer. `mOperationStack.add(currentInput);` is executing without any checks if `currentInput` is null (or length is greater than 0). Edit your code to match my answer. Proper placement of if-else statements is key. – mike47 Feb 28 '14 at 19:51