I have a calculator app that crashes when the equals button is pressed and there is nothing in the EditText that it getTexts from. I have looked at the other questions with similar situations, but those suggestions are not working. I am new to android and would like any help. I also have the issue if I have a "0" in my EditText.setText(), the "0" stays in front of the other numbers when they are pressed. Please let me know if you need more of the code to help.
Here is the Logcat info
09-08 07:58:32.915 13726-13726/com.ruthadeaton.bld3.calculator
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ruthadeaton.bld3.calculator, PID: 13726
java.lang.NumberFormatException: empty String
atsun.misc.FloatingDecimal.readJavaFormatString
(FloatingDecimal.java:1842)
at sun.misc.FloatingDecimal.parseFloat(FloatingDecimal.java:122)
at java.lang.Float.parseFloat(Float.java:451)
at com.ruthadeaton.bld3.calculator.MainActivity$26.onClick
(MainActivity.java :346)
at android.view.View.performClick(View.java:6597)
at android.view.View.performClickInternal(View.java:6574)
at android.view.View.access$3100(View.java:778)
at android.view.View$PerformClick.run(View.java:25885)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run
(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Here is my code:
buttonEqual.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mValueTwo=Float.parseFloat(edt1.getText() + "");
if (mAddition == true) {
edt1.setText(mValueOne + mValueTwo + "");
mAddition=false;
}
if (mSubtract == true) {
edt1.setText(mValueOne - mValueTwo + "");
mSubtract=false;
}
if (mMultiplication == true) {
edt1.setText(mValueOne * mValueTwo + "");
mMultiplication=false;
}
if (mDivision == true) {
edt1.setText(mValueOne / mValueTwo + "");
mDivision=false;
}
}
});
button0.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
edt1.setText(edt1.getText() + "0");
}
});
buttonAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mValueOne=Float.parseFloat(edt1.getText() + "");
mAddition=true;
edt1.setText(null);
}
});
buttonSub.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mValueOne=Float.parseFloat(edt1.getText() + "");
mSubtract=true;
edt1.setText(null);
}
});
buttonMul.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mValueOne=Float.parseFloat(edt1.getText() + "");
mMultiplication=true;
edt1.setText(null);
}
});
buttonDivision.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mValueOne=Float.parseFloat(edt1.getText() + "");
mDivision=true;
edt1.setText(null);
}
});
I have a calculator app that crashes when the equals button is pressed
and there is nothing in the EditText that it getTexts from.
Because you do not validate the input from users is valid or not. Obviously empty string is not a number that why the app crashes with NumberFormatExecption.
I also have the issue if I have a "0" in my EditText.setText(), the
"0" stays in front of the other numbers when they are pressed.
You can use TextWatcher to update the text view based on input from users.
I will guide you step by step how to fix those issues
First, define a method which validates input from users is a valid number or not.
private boolean isValidNumber(String numberInString) {
try {
Float.parseFloat(numberInString);
return true;
} catch (NumberFormatException e) {
return false;
}
}
Second, each time users press on a arithmetic operator (+, -, *, /) or equal (=) the app will get value from the edt1. Then write a method to do that to avoid duplicate code.
/**
* Get current input from user and try parse it to a number.
*
* #return a number if input is valid, otherwise return null.
*/
private Float getInputValue() {
Float possibleNumber = null;
String numberInString = edt1.getText().toString();
if (isValidNumber(numberInString)) {
possibleNumber = Float.parseFloat(numberInString);
}
return possibleNumber;
}
Third, prevent user from adding more than one zero number by using TextWatcher.
edt1.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
String content = s.toString();
if (content.startsWith("0") && content.length() == 2 && Character.isDigit(content.charAt(1))) {
edt1.setText(String.valueOf(content.charAt(1)));
edt1.setSelection(1);
}
}
});
Finally put it together.
public class MainActivity extends AppCompatActivity {
// Your variables here
...
// Make these two variables is Float instead of float.
Float mValueOne;
Float mValueTwo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Your init view here
...
edt1.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
String content = s.toString();
if (content.startsWith("0") && content.length() == 2 && Character.isDigit(content.charAt(1))) {
edt1.setText(String.valueOf(content.charAt(1)));
edt1.setSelection(1);
}
}
});
buttonEqual.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mValueTwo = getInputValue();
if (mValueOne == null || mValueTwo == null) {
// One of there or both of two values are not valid then do nothing.
return;
}
if (mAddition) {
edt1.setText(String.valueOf(mValueOne + mValueTwo));
mAddition = false;
}
if (mSubtract) {
edt1.setText(String.valueOf(mValueOne + mValueTwo));
mSubtract = false;
}
if (mMultiplication) {
edt1.setText(String.valueOf(mValueOne + mValueTwo));
mMultiplication = false;
}
if (mDivision) {
edt1.setText(String.valueOf(mValueOne + mValueTwo));
mDivision = false;
}
}
});
button0.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
edt1.setText(String.valueOf(edt1.getText().toString() + "0"));
edt1.setSelection(edt1.getText().length());
}
});
buttonAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mValueOne = getInputValue();
mAddition = true;
edt1.setText(null);
}
});
buttonSub.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mValueOne = getInputValue();
mSubtract = true;
edt1.setText(null);
}
});
buttonMul.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mValueOne = getInputValue();
mMultiplication = true;
edt1.setText(null);
}
});
buttonDivision.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mValueOne = getInputValue();
mDivision = true;
edt1.setText(null);
}
});
}
/**
* Get current input from user and try parse it to a number.
*
* #return a number if input is valid, otherwise return null.
*/
private Float getInputValue() {
Float possibleNumber = null;
String numberInString = edt1.getText().toString();
if (isValidNumber(numberInString)) {
possibleNumber = Float.parseFloat(numberInString);
}
return possibleNumber;
}
private boolean isValidNumber(String numberInString) {
try {
Float.parseFloat(numberInString);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}
It can't do a
mValueTwo=Float.parseFloat(edt1.getText() + "");
if edt1.getText() is empty.
You can correct this using a try-catch.
buttonEqual.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try{
mValueTwo=Float.parseFloat(edt1.getText() + "");
if (mAddition == true) {
edt1.setText(mValueOne + mValueTwo + "");
mAddition=false;
}
if (mSubtract == true) {
edt1.setText(mValueOne - mValueTwo + "");
mSubtract=false;
}
if (mMultiplication == true) {
edt1.setText(mValueOne * mValueTwo + "");
mMultiplication=false;
}
if (mDivision == true) {
edt1.setText(mValueOne / mValueTwo + "");
mDivision=false;
}
}catch(Exception e){
//eventually logging here
}
}
});
Else you can make some controls before doing the parseFloat
buttonEqual.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String edt = edt1.getText().toString();
if(edt.matches("")){
//something like a toast to signal
}else{
mValueTwo=Float.parseFloat(edt1.getText() + "");
if (mAddition == true) {
edt1.setText(mValueOne + mValueTwo + "");
mAddition=false;
}
if (mSubtract == true) {
edt1.setText(mValueOne - mValueTwo + "");
mSubtract=false;
}
if (mMultiplication == true) {
edt1.setText(mValueOne * mValueTwo + "");
mMultiplication=false;
}
if (mDivision == true) {
edt1.setText(mValueOne / mValueTwo + "");
mDivision=false;
}
}
}
});
You can set a hint attribute in your edit text that way it disappears anytime a number is actually inserted.
android:hint="0"
Also for the 0 being in front, maybe you want your edit text to be of the number format
android:inputType = "numberDecimal"
You didn't paste a stacktrace of the crash but I will assume it's a null pointer exception
if (edt1.getText != null) { /* do whatever executions */}
Related
i am recreating a typing app for education purposes. The goal is to type the words of the paragraph. When a word is correct the word turns green, the editText field get cleared and its the next words turn. At the end every word is green and than the app crashs because the Activity is looking for the next word to turn green but doesn't find something.
Sample Picture
Do you have a idea how I can stop the "search" at the end? I thought about saying:
if ("written words" equals "words of the text that should be written")
than, end the focus on the editText field and show the score "Success" for example.
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_paragraph_game);
paragraphTextView = findViewById(R.id.txtParagraph);
edtInput = findViewById(R.id.edtTextWriter);
timerView = findViewById(R.id.txtTimer);
edtInput.setInputType(InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
//Sofortiger Fokus auf Textfeld
edtInput.requestFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(edtInput, InputMethodManager.SHOW_IMPLICIT);
try {
refreshParagraph();
} catch (IOException e) {
e.printStackTrace();
}
setTitle(getString(R.string.paragraph_title));
edtInput.addTextChangedListener(this);
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
//empty method
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv//
if (s.toString().replace(" ", "").equals(wordList.get(wordIndex))) {
inputClean = true;
numberOfLetters += s.length();
wordIndex++;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
}
}
}
#Override
public void afterTextChanged(Editable s) {
if (inputClean) {
inputClean = false;
edtInput.setText("");
updateColor(paragraphTextView, paragraphInitializer.getNextIndex(wordIndex - 1));
} else if (!wordList.get(wordIndex).contains(s.toString().replace(" ", ""))) {
undoColorChange(paragraphTextView, paragraphInitializer.getCurrentIndex(), paragraphInitializer.lookaheadIndex(wordIndex));
}
}
protected void refreshParagraph() throws IOException {
paragraphInitializer = new ParagraphInitializer(this);
String paragraph = paragraphInitializer.getRandomParagraph();
wordList = paragraphInitializer.getWords(paragraph);
paragraphTextView.setText(paragraph, TextView.BufferType.SPANNABLE);
inputClean = false;
wordIndex = 0;
numberOfWords = paragraphInitializer.getWordCount();
countDownTimer = new CountDownTimer(Constants.MILLIS_IN_FUTURE, Constants.COUNTDOWN_INTERVAL) {
#SuppressLint("SetTextI18n")
#Override
public void onTick(long millisUntilFinished) {
timerView.setText("00:" + millisUntilFinished / 1000);
if ((millisUntilFinished / 1000) < 16)
timerView.setTextColor(Color.rgb(255, 34, 34));
}
#Override
public void onFinish() {
timerView.setText(getString(R.string.zero));
edtInput.setEnabled(false);
//initializeResultDialog();
//pushFirebaseValues();
//Intent intent = new Intent(ParagraphGameActivity.this, ResultParagraphActivity.class);
//startActivity(intent);
}
}.start();
}
private void updateColor(TextView paragraphTextView, int nextIndex) {
Spannable wordToSpan = new SpannableString(paragraphTextView.getText());
//Neu einfärben in Grün
wordToSpan.setSpan(new ForegroundColorSpan(Color.rgb(59, 226, 8)), 0, nextIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
paragraphTextView.setText(wordToSpan);
}
private void undoColorChange(TextView paragraphTextView, int currentIndex, int lookaheadIndex) {
Spannable wordToSpan = new SpannableString(paragraphTextView.getText());
//Neu einfärben falls Falsch
wordToSpan.setSpan(new ForegroundColorSpan(Color.rgb(226, 8, 8)), currentIndex, lookaheadIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
paragraphTextView.setText(wordToSpan);
}
private void pushFirebaseValues() {
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference(Constants.USER_SCORE);
String userName = getSharedPreferences(Constants.USER_PREFERENCE, Context.MODE_PRIVATE).getString(Constants.USER_NICK, getString(R.string.OK));
User user = new User(userName, numberOfLetters / 5, numberOfLetters, false);
if (userName != null) {
databaseReference.child(userName).setValue(user);
} else {
//DatabaseReference databaseReference1 = FirebaseDatabase.getInstance().getReference(Constants.USER_SCORE);
Query query = databaseReference.orderByChild("score-list");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot resultsSnapshot) {
for (DataSnapshot userSnapshot : resultsSnapshot.getChildren()) {
User user = new User(userName, numberOfLetters / 5, numberOfLetters, false);
userSnapshot.getRef().setValue(user);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
}
}
the error occures in the highlighted line. It looks like this:
vvvvvvvvvv
this line
^^^^^^^^^^
Thanks for your help! :)
----------- here is the complete logcat --------------
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myapplication, PID: 21599
java.lang.IndexOutOfBoundsException: Index: 8, Size: 8
at java.util.ArrayList.get(ArrayList.java:437)
at com.example.myapplication.ParagraphGameActivity.onTextChanged(ParagraphGameActivity.java:76)
at android.widget.TextView.sendOnTextChanged(TextView.java:11785)
at android.widget.TextView.setText(TextView.java:6965)
at android.widget.TextView.setText(TextView.java:6761)
at android.widget.EditText.setText(EditText.java:145)
at android.widget.TextView.setText(TextView.java:6713)
at com.example.myapplication.ParagraphGameActivity.afterTextChanged(ParagraphGameActivity.java:88)
at android.widget.TextView.sendAfterTextChanged(TextView.java:11816)
at android.widget.TextView$ChangeWatcher.afterTextChanged(TextView.java:15266)
at android.text.SpannableStringBuilder.sendAfterTextChanged(SpannableStringBuilder.java:1287)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:587)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:517)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:38)
at android.view.inputmethod.BaseInputConnection.replaceText(BaseInputConnection.java:867)
at android.view.inputmethod.BaseInputConnection.commitText(BaseInputConnection.java:199)
at com.android.internal.widget.EditableInputConnection.commitText(EditableInputConnection.java:177)
at com.android.internal.view.IInputConnectionWrapper.executeMessage(IInputConnectionWrapper.java:345)
at com.android.internal.view.IInputConnectionWrapper$MyHandler.handleMessage(IInputConnectionWrapper.java:93)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8512)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
Greetings
I am developeing app where i want to change the currency value from one to another, Like i have 2 edittext. one for USD Currency to enter and other for EURO currency to enter.
Now i want to enter value in 1 edittext and the calculated value should display in other and same for the other edit text box.
TextWatcher inputTextWatcher = new TextWatcher()
{
public void afterTextChanged(Editable s)
{
try {
Start_Calculate(""+s.toString());
}
catch (NumberFormatException nfe)
{ //or whatever exception you get
}
//do some handling if you need to
}
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
}
public void onTextChanged(CharSequence s, int start, int before, int count)
{
}
};
amountET.addTextChangedListener(inputTextWatcher);
TextWatcher inputTextWatcher1 = new TextWatcher() {
public void afterTextChanged(Editable s)
{
try {
Start_Calculate2(""+s.toString());
}
catch (NumberFormatException nfe)
{ //or whatever exception you get
}
}
public void beforeTextChanged(CharSequence s, int start, int count, int after){
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
};
amount2ET.addTextChangedListener(inputTextWatcher1);
FUNCTION ARE HERE:
public void Start_Calculate(String val)
{
String user_input_value="00.00";
try
{
// user_input_value=""+amountET.getText().toString();
user_input_value=""+val;
}
catch(NumberFormatException e)
{
user_input_value="00.00";
}
//*/
if(!user_input_value.equalsIgnoreCase(""))
{
if(user_input_value.length()<11)
{
try
{
user_amount=Double.parseDouble(""+user_input_value);
}
catch(NumberFormatException e)
{
user_amount=00.000;
}
if(user_amount>0)
{
user_amount=user_amount*1.0000001;
total_amount_to_send=((user_amount*to_amount_val)/from_amount_val);
// total_amount_to_send= total_amount_to_send+00.0000;
//String total=new DecimalFormat("##.##").format(total_amount_to_send);
// totalTV.setText(user_amount+" "+fromTV.getText().toString()+" = "+ total+" ("+toTV.getText().toString()+")");
// totalTV.setText(user_amount+" = "+ total);
// String finalVal= df.format(target_currency_val);
//total_calTV.setText("( "+user_amount+" × "+df.format(to_amount_val) +" = "+ total+" )");
String total="00.00";
DecimalFormat df = new DecimalFormat("#.####");
total=""+df.format(total_amount_to_send);
try
{
amount2ET.setText(""+total);//_amount_to_send+"");
}
catch(Exception e)
{
Log.e("Error in Calculate1: ",""+e.getMessage());
}
//showtoast(""+total);//_amount_to_send);
//usdTV.setText(""+user_amount+" ("+fromTV.getText().toString()+")");
//pkrTV.setText(""+ total+" ("+toTV.getText().toString()+")");
}
else
{
}
}
else
{
}
}
}
public void Start_Calculate2(String val)
{
//String user_input_value="0";
//String user_input_value=""+val;
String user_input_value="0";
try
{
//user_input_value=""+amount2ET.getText().toString();
user_input_value=val;
}
catch(NumberFormatException e)
{
user_input_value="00.00";
}
//*/
if(!user_input_value.equalsIgnoreCase(""))
{
if(user_input_value.length()<11)
{
try
{
user_amount=Double.parseDouble(""+user_input_value);
}
catch(NumberFormatException e)
{
user_amount=00.00;
}
if(user_amount>0)
{
user_amount=user_amount*1.0000001;
total_amount_to_send=((user_amount*from_amount_val)/to_amount_val);
// total_amount_to_send= total_amount_to_send+00.0000;
//String total=new DecimalFormat("##.##").format(total_amount_to_send);
// totalTV.setText(user_amount+" "+toTV.getText().toString()+" = "+ total+" ("+fromTV.getText().toString()+")");
// totalTV.setText(user_amount+" = "+ total);
//DecimalFormat df = new DecimalFormat("#.##");
// String finalVal= df.format(target_currency_val);
//total_calTV.setText("( "+user_amount+" × "+df.format(to_amount_val) +" = "+ total+" )");
String total=new DecimalFormat("##.##").format(total_amount_to_send);
try
{
amountET.setText(""+total);//_amount_to_send);
}
catch(Exception e)
{
Log.e("Error in Calculate-2: ",""+e.getMessage());
}
//showtoast(""+total);//_amount_to_send);
//usdTV.setText(""+user_amount+" ("+fromTV.getText().toString()+")");
//pkrTV.setText(""+ total+" ("+toTV.getText().toString()+")");
}
else
{
//totalTV.setText("");
//total_calTV.setText("");
}
}
else
{
//totalTV.setText("");
//total_calTV.setText("");
}
}
}
It is because you get infinite loop.
amount2ET.setText will toggle another "afterTextChanged" let you repeat and repeat call of Start_Calculate.
You should remove the listener before set the text
amountET.removeTextChangedListener(inputTextWatcher)
try
{
amountET.setText(""+total);//_amount_to_send);
}
catch(Exception e)
{
Log.e("Error in Calculate-2: ",""+e.getMessage());
}
amountET.addTextChangedListener(inputTextWatcher);
Or you can set a global flag true when updating so you can dismiss another Start_Calculate:
boolean updating = false;
public void afterTextChanged(Editable s)
{
try {
if (!updating)
Start_Calculate(""+s.toString());
}
catch (NumberFormatException nfe)
{ //or whatever exception you get
}
//do some handling if you need to
}
Inside Start_Calculate:
updating = true;
try
{
amountET.setText(""+total);//_amount_to_send);
}
catch(Exception e)
{
Log.e("Error in Calculate-2: ",""+e.getMessage());
}
updating = false;
**> I have a Edit Text with hint 0.00
Now i want to input text
If i press 5 it should appear 0.05
next if i press 4 it should come like 0.54**
this is the correct answer for my requirement
public static void decimalFormat(final EditText editText) {
editText.addTextChangedListener(new TextWatcher() {
String before = "";
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
before = s.toString();
}
#Override
public void afterTextChanged(Editable s) {
if (!before.equalsIgnoreCase(s.toString())
&& !TextUtils.isEmpty(s.toString().trim())) {
before = s.toString();
String tvStr = s.toString();
if (tvStr.contains("-") || tvStr.equals(".")) {
editText.setText("");
}
if (!tvStr.equals("") && !tvStr.equals(".")) {
String cleanString = getFormatedNumber(tvStr, 2);
editText.setText(cleanString);
try {
editText.setSelection(cleanString.length());
return;
} catch (IndexOutOfBoundsException e) {
editText.setSelection(cleanString.length() - 1);
return;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
});
}
public static String getFormatedNumber(String text, int decimalPoint) {
String cleanString = text.replaceAll("[,.|\\s]", "");
if (TextUtils.isEmpty(cleanString)) {
return "0.00";
}
NumberFormat formatter = new DecimalFormat("#,##0.00");
double number = Double.parseDouble(cleanString) / (long) Math.pow(10.0, decimalPoint);
return formatter.format(number).toString();
}
I am new to android so i was trying to make calculator as my first app. I have done everything but i only have one problem
I have a leading 0 when the value is 0. Then it shows 0.0 after i click Clear i want to change it to 0 I don’t know how to change it.
MainActivity
public class MainActivity extends Activity implements OnClickListener {
private TextView calculatorDisplay;
private static final String DIGITS = "0123456789.";
private Boolean userIsInTheMiddleOfTypingANumber = false;
DecimalFormat df = new DecimalFormat("############");
CalculatorBrain brain;
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
brain = new CalculatorBrain();
calculatorDisplay = (TextView) findViewById(R.id.textView1);
df.setMinimumFractionDigits(0);
df.setMinimumIntegerDigits(1);
df.setMaximumIntegerDigits(8);
findViewById(R.id.button0).setOnClickListener(this);
findViewById(R.id.button1).setOnClickListener(this);
findViewById(R.id.button2).setOnClickListener(this);
findViewById(R.id.button3).setOnClickListener(this);
findViewById(R.id.button4).setOnClickListener(this);
findViewById(R.id.button5).setOnClickListener(this);
findViewById(R.id.button6).setOnClickListener(this);
findViewById(R.id.button7).setOnClickListener(this);
findViewById(R.id.button8).setOnClickListener(this);
findViewById(R.id.button9).setOnClickListener(this);
findViewById(R.id.buttonAdd).setOnClickListener(this);
findViewById(R.id.buttonSubtract).setOnClickListener(this);
findViewById(R.id.buttonMultiply).setOnClickListener(this);
findViewById(R.id.buttonDivide).setOnClickListener(this);
findViewById(R.id.buttonSquareRoot).setOnClickListener(this);
findViewById(R.id.buttonInvert).setOnClickListener(this);
findViewById(R.id.buttonCos).setOnClickListener(this);
findViewById(R.id.buttonSin).setOnClickListener(this);
findViewById(R.id.buttonToggleSign).setOnClickListener(this);
findViewById(R.id.buttonDecimalPoint).setOnClickListener(this);
findViewById(R.id.buttonEquals).setOnClickListener(this);
findViewById(R.id.buttonClear).setOnClickListener(this);
findViewById(R.id.buttonClearMemory).setOnClickListener(this);
findViewById(R.id.buttonAddToMemory).setOnClickListener(this);
findViewById(R.id.buttonSubtractFromMemory).setOnClickListener(this);
findViewById(R.id.buttonRecallMemory).setOnClickListener(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ActionBar actionBar = getActionBar();
actionBar.setDisplayShowHomeEnabled(false);
actionBar.setDisplayShowTitleEnabled(false);
actionBar.hide();
}
}
// #Override
public void onClick(View view) {
String buttonPressed = ((Button) view).getText().toString();
// String digits = "0123456789.";
if (DIGITS.contains(buttonPressed)) {
// digit was pressed
if (userIsInTheMiddleOfTypingANumber) {
calculatorDisplay.append(buttonPressed);
} else {
calculatorDisplay.setText(buttonPressed);
userIsInTheMiddleOfTypingANumber = true;
}
} else {
// operation was pressed
if (userIsInTheMiddleOfTypingANumber) {
brain.setOperand(Double.parseDouble(calculatorDisplay.getText().toString()));
userIsInTheMiddleOfTypingANumber = false;
}
brain.performOperation(buttonPressed);
calculatorDisplay.setText(df.format(brain.getResult()));
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save variables on screen orientation change
outState.putDouble("OPERAND", brain.getResult());
outState.putDouble("MEMORY", brain.getMemory());
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore variables on screen orientation change
brain.setOperand(savedInstanceState.getDouble("OPERAND"));
brain.setMemory(savedInstanceState.getDouble("MEMORY"));
calculatorDisplay.setText(df.format(brain.getResult()));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
CalculatorBrain
public class CalculatorBrain {
// 3 + 6 = 9
// 3 & 6 are called the operand.
// The + is called the operator.
// 9 is the result of the operation.
private double operand = 0;
private double waitingOperand = 0;
private String waitingOperator = "";
private double calculatorMemory = 0;
public void setOperand(double operand) {
this.operand = operand;
}
public double getResult() {
return operand;
}
// used on screen orientation change
public void setMemory(double calculatorMemory) {
this.calculatorMemory = calculatorMemory;
}
// used on screen orientation change
public double getMemory() {
return calculatorMemory;
}
public String toString() {
return Double.toString(operand);
}
protected double performOperation(String operator) {
/*
* If you are using Java 7, then you can use switch in place of if statements
*
* switch (operator) {
* case "MC":
* calculatorMemory = 0;
* break;
* case "M+":
* calculatorMemory = calculatorMemory + operand;
* break;
* }
*/
if (operator.equals("MC")) {
calculatorMemory = 0;
} else if (operator.equals("M+")) {
calculatorMemory = calculatorMemory + operand;
} else if (operator.equals("M-")) {
calculatorMemory = calculatorMemory - operand;
} else if (operator.equals("MR")) {
operand = calculatorMemory;
} else if (operator.equals("C")) {
operand = 0;
waitingOperator = "";
waitingOperand = 0;
calculatorMemory = 0;
} else if (operator.equals("Sqrt")) {
operand = Math.sqrt(operand);
} else if (operator.equals("1/x")) {
if (operand != 0) {
operand = 1 / operand;
}
} else if (operator.equals("+/-")) {
operand = -operand;
} else if (operator.equals("sin")) {
operand = Math.sin(operand);
} else if (operator.equals("cos")) {
operand = Math.cos(operand);
} else {
performWaitingOperation();
waitingOperator = operator;
waitingOperand = operand;
}
return operand;
}
protected void performWaitingOperation() {
if (waitingOperator.equals("+")) {
operand = waitingOperand + operand;
} else if (waitingOperator.equals("*")) {
operand = waitingOperand * operand;
} else if (waitingOperator.equals("-")) {
operand = waitingOperand - operand;
} else if (waitingOperator.equals("/")) {
if (operand != 0) {
operand = waitingOperand / operand;
}
}
}
This is happening because getResult() retuns a double.
If you want a 0 to be displayed in place of 0.0, perform a check like this:
Replace:
calculatorDisplay.setText(df.format(brain.getResult()));
with:
if (new Double(brain.getResult()).equals(0.0)){
calculatorDisplay.setText("" + 0);
} else {
calculatorDisplay.setText(df.format(brain.getResult()));
}
This should solve your problem.
Edit 1:
Try the following changes:
if (DIGITS.contains(buttonPressed)) {
// digit was pressed
if (userIsInTheMiddleOfTypingANumber) {
calculatorDisplay.append(buttonPressed);
} else {
if (buttonPressed.equals("0") && !calculatorDisplay.getText().toString().equals("0")) {
calculatorDisplay.setText("0");
} else if (!buttonPressed.equals("0")) {
if (buttonPressed.equals(".")) {
calculatorDisplay.setText("0.");
} else {
calculatorDisplay.setText(buttonPressed);
}
userIsInTheMiddleOfTypingANumber = true;
}
}
}
You have to use text watcher listener on your text view:
textview.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
if(textview.gettText().toString().equals("0"))
{
textview.settText("0.0");
}
}
});
I want to be able to calculate something depending on the input in 2 of 3 EditText. For Example: I make an input in ET 1 and 2 -> i get a calculation in ET 3. ET 1 and 3 -> calculation in ET 2... and so on.
I get it to work with 2 EditText but with 3 I get an StackOverFlowError.
private class GenericTextWatcher implements TextWatcher {
private View view;
private GenericTextWatcher(View view) {
this.view = view;
}
public void beforeTextChanged(CharSequence charSequence, int i, int i1,
int i2) {
}
public void onTextChanged(CharSequence charSequence, int i, int i1,
int i2) {
}
public void afterTextChanged(Editable editable) {
switch (view.getId()) {
case R.id.liter_input:
try {
if (amount_widget.getText().toString().equals(" ") == false
|| literPrice_widget.getText().toString()
.equals(" ") == false
|| price_widget.getText().toString().equals(" ") == false) {
double editTextCalc = Double.parseDouble(amount_widget
.getText().toString())
* Double.parseDouble(literPrice_widget
.getText().toString());
editTextCalc = Math.round(editTextCalc * 100) / 100.0;
price_widget.setText(String.valueOf(decimalFormat
.format(editTextCalc)));
}
} catch (Exception e) {
// TODO: handle exception
}
break;
case R.id.literprice_input:
try {
if (amount_widget.getText().toString().equals(" ") == false
|| literPrice_widget.getText().toString()
.equals(" ") == false
|| price_widget.getText().toString().equals(" ") == false) {
double editTextCalc = Double.parseDouble(amount_widget
.getText().toString())
* Double.parseDouble(literPrice_widget
.getText().toString());
editTextCalc = Math.round(editTextCalc * 100) / 100.0;
price_widget.setText(String.valueOf(decimalFormat
.format(editTextCalc)));
}
} catch (Exception e) {
// TODO: handle exception
}
break;
case R.id.price_input:
try {
if (amount_widget.getText().toString().equals(" ") == false
|| literPrice_widget.getText().toString()
.equals(" ") == false
|| price_widget.getText().toString().equals(" ") == false) {
double editTextCalc = Double.parseDouble(amount_widget
.getText().toString())
/ Double.parseDouble(price_widget.getText()
.toString());
editTextCalc = Math.round(editTextCalc * 100) / 100.0;
literPrice_widget.setText(String.valueOf(decimalFormat
.format(editTextCalc)));
}
} catch (Exception e) {
// TODO: handle exception
}
break;
}
}
}
OK i just started to review my code again. Why hasn't anyone found an answer? It's really not that hard.
So i just just surrounded the if-statements in every try block with another if-statement which looks like this:
if(edittext.isFocused()){
try-catch block
}
And now everything works just fine. There is no StackOverflowException anymore because the textwatcher only starts it's work where the edittext is focused. The text changes do not trigger an infinit loop anymore.
You should check if change in an EditText happened because of changes made in other EditText. Create a boolean field in the class and initialize it with false:
private boolean mIsChanging = false;
In afterTextChanged() check if this field is false or exit otherwise:
public void afterTextChanged(Editable editable) {
if (mIsChanging) {
return;
}
mIsChanging = true;
// Then do what you did previously...
mIsChanging = false;
}
With Editable is possible, you need to use hashCodeFunction
#Override
public void afterTextChanged(Editable s) {
if (editText.getText().hashCode() == s.hashCode()) {
// some
}
}