Touch Calculator in Android
Asked Answered
U

2

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

Unlearn answered 13/2, 2014 at 5:31 Comment(9)
Realistically, nobody is going to read THAT much code. Isolate the problem. Help us help you.Rawley
And tell us which line the exception happens in? Which line is 59?Adjudicate
You forgot to initialize userInputText TextView...Nitrobenzene
You have StringIndexOutOfBoundException which means you are calling something like myString.getCharAt(56) while your string is only 54 long for example.Arundinaceous
@Android-Developer I dont know how to solve it.can you tell me if you know exactly?Osmious
what you have on line 121?Arundinaceous
you are getting error at currentInput.charAt(0), try applying condition like if(!currentInput.isEmpty())Camber
Can you post the whole MainActivity.java file? I'm trying to find the line which threw the exception but you posted the code without package statement and without the imports.Vestryman
you have to understand this #218884Recoil
C
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

Color answered 13/2, 2014 at 5:38 Comment(13)
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.Osmious
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.Osmious
Is there any way to get a outputOsmious
is logcat giving you the same error after initializing all textviews separately?Color
Now logcat error doesnt occur.But If I press +(plus) button, Calculator unfortunately stopped Alert dialog box appears. then suddently it closes the emulator.Osmious
so when your app crashes, your logcat will read the exception/error, post thatColor
check it.I post the new logcat imageOsmious
U check that logcat image.Osmious
yes, but its not from at the time of the crash, scroll up or see where you can find the error/exception postsColor
I find and post the Logcat image :)Osmious
can you able to check it and tell meOsmious
Sorry to butt in. Is the exception still stringindexoutofbounds?Hakodate
What code is at line 121? Seems some array isnt populated but x pos is being requestedColor
T
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.

Tambour answered 28/2, 2014 at 6:44 Comment(6)
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.Tambour
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.Tambour
Where I have to include that methodOsmious
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) ...Tambour
What you told that I changed the method.Check it.But still error remains sameOsmious
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.Tambour

© 2022 - 2024 — McMap. All rights reserved.