Calculator with single edittext field - java

I am new to android development and I am trying to develop a calculator with single edit text field. It's not showing any compiler error but it crashes as soon as I press any button. I'm first taking the input for num1 and clearing the edit text field followed by a switch case to detect the operation and collecting the data of the second number.
public class MainActivity extends Activity implements OnClickListener{
EditText ino;
Button btnadd;
Button btnsub;
Button btnmult;
Button btndiv;
Button btneq;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ino=(EditText) findViewById(R.id.ino);
btnadd=(Button) findViewById(R.id.add);
btndiv=(Button) findViewById(R.id.div);
btnsub=(Button) findViewById(R.id.sub);
btnmult=(Button) findViewById(R.id.mult);
btneq=(Button) findViewById(R.id.eq);
btnadd.setOnClickListener((OnClickListener) this);
btnsub.setOnClickListener(this);
btnmult.setOnClickListener(this);
btndiv.setOnClickListener(this);
}
#Override
public void onClick(View v)
{
float num1=0,num2=0,res=0;
String xyz="",ans;
num1=Float.parseFloat(ino.getText().toString());
ino.setText(xyz);
switch(v.getId())
{
case R.id.add:
num2=Float.parseFloat(ino.getText().toString());
res=num2+num1;
ans=Float.toString(res);
break;
case R.id.div:
num2=Float.parseFloat(ino.getText().toString());
ino.setText(xyz);
res=num1/num2;
ans=Float.toString(res);
ino.setText(ans);
break;
case R.id.mult:
num2=Float.parseFloat(ino.getText().toString());
ino.setText(xyz);
res=num2*num1;
ans=Float.toString(res);
ino.setText(ans);
break;
case R.id.sub:
num2=Float.parseFloat(ino.getText().toString());
ino.setText(xyz);
res=num1-num2;
ans=Float.toString(res);
ino.setText(ans);
break;
case R.id.eq:
ans=Float.toString(res);
ino.setText(ans);
break;
default: break;
}
}
}
Here is the copy of stack trace.
12-28 00:49:52.646 2125-2125/com.example.rishabh.calculator2
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.rishabh.calculator2, PID: 2125
java.lang.NumberFormatException: Invalid float: ""
at java.lang.StringToReal.invalidReal(StringToReal.java:63)
at java.lang.StringToReal.parseFloat(StringToReal.java:308)
at java.lang.Float.parseFloat(Float.java:306)
at com.example.rishabh.calculator2.MainActivity.onClick(MainActivity.java:56)
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)

Your code contains several problems. The first is that Float.parseFloat() will throw a java.lang.NumberFormatException if the string is empty or contains letters. This should be handled with try/catch.
The second problem is that the variables num1, num2 and res cannot be declared locally, because they will be initialized to 0.0 every time a button is clicked.
For the calculator to work it is necessary to remember the operation that is going to be performed when the user clicks the "equals"-button. The previous clicked button can be stored using an int.
The following code is tested and works.
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.view.View.*;
import android.view.View;
public class MainActivity extends Activity implements OnClickListener {
EditText ino;
Button btnadd;
Button btnsub;
Button btnmult;
Button btndiv;
Button btneq;
private float num1 = 0;
private float num2 = 0;
private float res = 0;
private int operation = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ino=(EditText) findViewById(R.id.ino);
btnadd=(Button) findViewById(R.id.add);
btndiv=(Button) findViewById(R.id.div);
btnsub=(Button) findViewById(R.id.sub);
btnmult=(Button) findViewById(R.id.mult);
btneq=(Button) findViewById(R.id.eq);
btnadd.setOnClickListener(this);
btnsub.setOnClickListener(this);
btnmult.setOnClickListener(this);
btndiv.setOnClickListener(this);
btneq.setOnClickListener(this);
}
#Override
public void onClick(View v)
{
String s = ino.getText().toString();
try
{
Float.parseFloat(s);
}
catch (NumberFormatException e)
{
s = "0.0";
}
String xyz="",ans;
ino.setText(xyz);
switch(v.getId())
{
case R.id.eq:
num1=Float.parseFloat(s);
switch (operation) {
case R.id.add:
res = num2 + num1;
break;
case R.id.sub:
res = num2 - num1;
break;
case R.id.mult:
res = num2 * num1;
break;
case R.id.div:
res = num2 / num1;
break;
default:
res = 0;
break;
}
ans=Float.toString(res);
ino.setText(ans);
break;
}
num2 = Float.parseFloat(s);
operation = v.getId();
}
}

From your code it is clear that it will throw java.lang.NumberFormatException exception. If the edit text contains invalid string or empty string the parseFloat method will throw a NumberFormatException.
You are setting the edit text value to empty string in the following code (where xyz is initialised to empty string):
ino.setText(xyz);
After that you are trying to parse the edit text data to float and it will throw an exception. You need to catch those exceptions and properly handle it in your code.
try
{
num1=Float.parseFloat(ino.getText().toString());
}
catch (NumberFormatException e)
{
num1 = 0.0f;
}
(Similar like this, you need to handle all the parseFloat calls)

In your LogCat, I see the following:
java.lang.NumberFormatException: Invalid float: "" at java.lang.StringToReal.invalidReal(StringToReal.java:63)
Many times in your code you are trying to parse a String value and store it as a float, which isn't going to work:
num1=Float.parseFloat(ino.getText().toString());
Instead you should use the following to convert to String to a float:
num1 = Float.valueOf(ino.getText().toString());

Related

Android: switch case & random number code in the case

Android, java, studio 4.0.1
Trying to code by my own, I am facing an issue which I do not understand from the compiler statements.
Basically, when you click a radio button, a random number is generated in the textview field.
My problem is that the random code written in the case of the clicked radio button is not accepted by the compiler.
Here is the code:
package com.example.random;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.RadioButton;
import android.widget.TextView;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onRadioButtonClicked(View view) {
// Is the button now checked?
boolean checked = ((RadioButton) view).isChecked();
TextView MytextView = (TextView)findViewById(R.id.MytextView);
int random;
int random2;
// Check which radio button was clicked
switch(view.getId()) {
case R.id.radioButton01:
if (checked)
// 0 or 1 code
random = getRandomNumber(0,1);
MytextView.setText(random.toString());
break;
case R.id.radioButton1to6:
if (checked)
// 1 to 6 code
random2 = getRandomNumber(1,6);
MytextView.setText(random2.toString());
break;
}
}
private int getRandomNumber(int min,int max) {
return (new Random()).nextInt((max - min) + 1) + min;
}
}
I presume that the 2 lines 'Int random;' are wrong, but the compiler seems to want to have them here.
I would have understood that the line 'random = getRandomNumber(0,1);' would have be sufficient in the case part of the code, but the compiler marks 'random' in red.
So far, the compiler says: 'error: int cannot be dereferenced in the MytextView.setText(random.toString());' of the //0 or 1 code part.
I would like to understand what I am missing here. Thanks in advance.
(Or asked simpler: how does one code a random function in a switch/case ?)
ok I found the solution. A possible working code is:
public void onRadioButtonClicked(View view) {
// Is the button now checked?
boolean checked = ((RadioButton) view).isChecked();
TextView MytextView = (TextView)findViewById(R.id.MytextView);
final Random rnd = new Random();
// Check which radio button was clicked
switch(view.getId()) {
case R.id.radioButton01:
if (checked)
// 0 or 1 code
MytextView.setText(String.valueOf(rnd.nextInt(3-0) + 0));
break;
case R.id.radioButton1to6:
if (checked)
// Dice 1 to 6 code
MytextView.setText("1 to 6");
break;
case R.id.radioButton1to10:
if (checked)
// 1 to 10 code
MytextView.setText("1 to 10");
break;
}
}
And the 'private int getRandomNumber' at the end can be deleted. No need of it.

How to validate decimal input not allowing alone "." and empty field?

I'm writing a calculator on Android Studio, in Java, and the app crashes if the user call the result with a dot "." alone or let the EditText field in blank.
I'm looking for a solution for not allowing these two conditions happening, together or individualy, in each of the three fields.
I've already tried TextWatcher and if/else but without success.
The .xml file where the editText field are designed is already set for decimalNumber.
I've already tried this:
if(myfieldhere.getText().toString().equals(".")){myfieldhere.setText("0");}
For each "valor line" and else for the "finalresult" line if everything is fine. Both inside the setOnClickListener block. This is my code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.peso_layout);
result = findViewById(R.id.layresult);
conc = findViewById(R.id.layconc);
dose = findViewById(R.id.laydose);
peso = findViewById(R.id.laypeso);
calc = findViewById(R.id.laycalcpeso);
calc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
float valor1 = Float.parseFloat(peso.getText().toString());
float valor2 = Float.parseFloat(conc.getText().toString());
float valor3 = Float.parseFloat(dose.getText().toString());
float finalresult = valor1 * valor2 * valor3;
result.setText("The result is: " + finalresult);
}
});
}
The ideal output should be the app not crashing if these two conditions happen and sending an error message to the user that input is invalid.
What i'm receiving is the app crashing.
Thank you very much. I'm very beginner in Java and I'm few days struggling with this.
Dear Friend, Your directly trying to convert string input into float and then after your check value but do your code like Below.
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
EditText edt1,edt2;
TextView txtans;
Button btnsum;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edt1=findViewById(R.id.edt1);
edt2=findViewById(R.id.edt2);
txtans=findViewById(R.id.txtans);
btnsum=findViewById(R.id.btnsum);
btnsum.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v.getId()==R.id.btnsum){
float n1,n2;
String value1=edt1.getText().toString();
String value2=edt2.getText().toString();
if(value1.equals("") || value1.equals(".")){
n1=0;
}else {
n1= Float.parseFloat(value1);
}
if(value2.equals("")|| value2.equals(".")){
n2=0;
}else{
n2= Float.parseFloat(value2);
}
float ans=n1+n2;
txtans.setText(ans+"");
}
}
}
See In above code, First get value from edittext and then check wheather it contain null or "." inside it. if it contains then store 0.0 value in some variable. then after make sum and display in textbox.
calc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String myvalor = myfieldhere.getText().toString();
if(myvalor.equals(".") || myvalor.isEmpty())
{
// toast error : incorrect value
return;
}
try
{
float valor1 = Float.parseFloat(peso.getText().toString());
float valor2 = Float.parseFloat(conc.getText().toString());
float valor3 = Float.parseFloat(dose.getText().toString());
float finalresult = valor1 * valor2 * valor3;
result.setText("The result is: " + finalresult);
}
catch(Exception exp){// toast with exp.toString() as message}
}
});
use TextUtils for check empty String its better
if(TextUtils.isEmpty(peso.getText().toString())||
TextUtils.isEmpty(conc.getText().toString())||
TextUtils.isEmpty(dose.getText().toString())){
return;
}

My app crashes whenever my EditText is empty and I press a button

The problem is that each time I click on the button in my app, then whenever one of my EditText or both are empty, the app will crash.
The idea is that I will write the calories in the EditText called caloriesIn and it will put out an int in the caloriesOut which is a textfield.
The same idea goes for "fat".
The problem just to sum up is that if I write something in the calories, but don't write anything in fat, or just don't write anything in either of them, the app will crash.
My Code:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View view) {
EditText caloriesIn = (EditText) findViewById(R.id.caloriesIn);
EditText fatIn = (EditText) findViewById(R.id.fatIn);
TextView caloriesOut = (TextView) findViewById(R.id.caloriesOut);
TextView fatOut = (TextView) findViewById(R.id.fatOut);
int calories = Integer.parseInt(caloriesIn.getText().toString());
int fat = Integer.parseInt(fatIn.getText().toString());
int caloriesResult = calories;
int fatResult = fat;
caloriesOut.setText(caloriesResult + "");
fatOut.setText(fatResult + "");
}
});
}
}
Crash report:
03-22 17:20:02.512 22193-22193/ottolopez.healthynote I/Choreographer: Skipped 47 frames! The application may be doing too much work on its main thread.
03-22 17:20:02.556 22193-22193/ottolopez.healthynote V/View: dispatchProvideAutofillStructure(): not laid out, ignoring 0 children of 1073741833
03-22 17:20:02.561 22193-22193/ottolopez.healthynote I/AssistStructure: Flattened final assist data: 2936 bytes, containing 1 windows, 11 views
03-22 17:20:05.047 22193-22193/ottolopez.healthynote D/AndroidRuntime: Shutting down VM
03-22 17:20:05.049 22193-22193/ottolopez.healthynote E/AndroidRuntime: FATAL EXCEPTION: main
Process: ottolopez.healthynote, PID: 22193
java.lang.NumberFormatException: For input string: ""
at java.lang.Integer.parseInt(Integer.java:620)
at java.lang.Integer.parseInt(Integer.java:643)
at ottolopez.healthynote.MainActivity$1.onClick(MainActivity.java:28)
at android.view.View.performClick(View.java:6294)
at android.view.View$PerformClick.run(View.java:24770)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Define this methode on your activity :
public boolean isParsable(String input){
boolean parsable = true;
try{
Integer.parseInt(input);
}catch(NumberFormatException e){
parsable = false;
}
return parsable;
}
Then updated your code like this :
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View view) {
EditText caloriesIn = (EditText) findViewById(R.id.caloriesIn);
EditText fatIn = (EditText) findViewById(R.id.fatIn);
TextView caloriesOut = (TextView) findViewById(R.id.caloriesOut);
TextView fatOut = (TextView) findViewById(R.id.fatOut);
String caloriesString = caloriesIn.getText().toString();
int calories = 0;
if (isParsable(caloriesString)){
calories = Integer.parseInt(caloriesString);
int caloriesResult = calories;
caloriesOut.setText(caloriesResult + "");
}
String fatString = caloriesIn.getText().toString();
int fat = 0;
if (isParsable(fatString)){
fat = Integer.parseInt(fatString);
int fatResult = fat;
fatOut.setText(fatResult + "");
}
}
});
}
public static boolean isParsable(String input){
boolean parsable = true;
try{
Integer.parseInt(input);
}catch(NumberFormatException e){
parsable = false;
}
return parsable;
}
}
Hope this helps
int calories = Integer.parseInt(caloriesIn.getText().toString());
int fat = Integer.parseInt(fatIn.getText().toString());
The main problem is in these lines, it will give error is you pass any character here or leave it blank, to solve these add these lines to your code
String calIn = caloriesIn.getText().toString(); //first take input in String for checking
String fatInStr = fatIn.getText().toString(); //first take input in String for checking
if (calIn.isEmpty()) {
Toast.makeText(...);//inform user that calories input field is empty
return;
} else if (fatInStr.isEmpty()) {
Toast.makeText(...);//inform user that fat input field is empty
return;
} else if (!calIn.matches("[0-9]+")) {
Toast.makeText(...);//inform user that calories input field contains invalid data
return;
} else if (!fatInStr.matches("[0-9]+")) {
// Toast.makeText(...);//inform user that fat input field contains invalid data
return;
}
int calories = Integer.parseInt(calIn.trim()); // trim method removes any leading and trailing spaces
int fat = Integer.parseInt(fatInStr.trim());
Now app is safe when text is empty and is not a digit :)
The thing is Integer.parseInt() doesn't handle empty string which is not a number. So, you need to check for text emptiness and then use Integer.parseInt(). Also you can use isDigitsOnly method before using parseInt.

Making Quiz App in Android with Radio Buttons

I'm making a Quizz App for Android with 10 Questions, all of them with 4 Radio Buttons, and one button at the end to show the score. The problem is when I choose the correct answer it gives 5 points, but if I check another radio button the points will stay 5 and if I press again it sums 5. What is the best way to code this?
Here is the code:
package com.example.android.quizproject;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.RadioButton;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
int points = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void firstRadioButtons (View view){
boolean checked = ((RadioButton) view).isChecked();
switch (view.getId()) {
case R.id.questionOneA:
if (checked)
points += 0;
break;
case R.id.questionOneB:
if (checked)
points += 0;
break;
case R.id.questionOneC:
if (checked)
points += 5;
break;
case R.id.questionOneD:
if (checked)
points += 0;
break;
}
}
public void showScore (View view) {
TextView scoreTextView = (TextView) findViewById(R.id.score);
scoreTextView.setText(" " + points);
}
}
You can make use of a counter vvariable which checks if the question has been previousy answered or not. Modify part of your code to this
public void firstRadioButtons (View view){
boolean checked = ((RadioButton) view).isChecked();
int count=0;
switch (view.getId()) {
case R.id.questionOneA:
if (checked)
{
if(count!=0){
points-=5;
count=0;
}
}
break;
case R.id.questionOneB:
if (checked)
{
if(count!=0){
points-=5;
count=0;
}
}
break;
case R.id.questionOneC:
if (checked){
points += 5;
count+=1;}
break;
case R.id.questionOneD:
if (checked)
{
if(count!=0){
points-=5;
count=0;
}
}
break;
}
}
Actually, the way you described it, it's common sense. If you click the right answer once, it will set it to 5, but if you press any other it will add 0 to it.
In general, it will print out 5 since you got the answer correct once, and the other questions are set to 0. There's really nothing to fix here, it's kind of common sense that your variable wouldn't read other than 5. Just like Abhriya said, you could add a counter increment value as done in ( her / his ) example.

Rolling a dice based on number of sides

EDIT: See included error log.
I am trying to create a simple app to roll different sided dice in Android Studio.
This is my code so far:
MainActivity.java
package com.example.thomb.tutorialspoint;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.RadioButton;
import android.widget.TextView;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.buttonRoll);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
int roll = RollDice(sidesChosen);
TextView tv1 = (TextView)findViewById(R.id.textView);
tv1.setText(roll);
setContentView(tv1);
}
});
}
public int sidesChosen;
public int RollDice(int sides) {
Random r = new Random();
return r.nextInt(sides)+1;
} //method
public void onRadioButtonClicked(View view) {
// Is the button now checked?
boolean checked = ((RadioButton) view).isChecked();
// Check which radio button was clicked
switch(view.getId()) {
case R.id.radioButtonD4:
if (checked)
sidesChosen = 4;
break;
case R.id.radioButtonD6:
if (checked)
sidesChosen = 6;
break;
case R.id.radioButtonD8:
if (checked)
sidesChosen = 8;
break;
case R.id.radioButtonD10:
if (checked)
sidesChosen = 10;
break;
case R.id.radioButtonD12:
if (checked)
sidesChosen = 12;
break;
case R.id.radioButtonD20:
if (checked)
sidesChosen = 20;
break;
} //switch
} //method
} //class
This is how the layout looks like:
http://i.imgur.com/IeIbMlz.png
The app crashes when i click the roll button, but I've no idea why. The ID's are all correct and the radio buttons works as expected.
I am using API level 25. I am fairly new to Java, but I am quite familiar with C#, so the problem may lie in the code syntax, although Android Studio reports no errors. Let me know if you need to see the XML for the layout as well.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.thomb.tutorialspoint, PID: 5029
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.view.ViewGroup.addViewInner(ViewGroup.java:4310)
at android.view.ViewGroup.addView(ViewGroup.java:4146)
at android.view.ViewGroup.addView(ViewGroup.java:4087)
at android.view.ViewGroup.addView(ViewGroup.java:4060)
at android.support.v7.app.AppCompatDelegateImplV9.setContentView(AppCompatDelegateImplV9.java:279)
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:145)
at com.example.thomb.tutorialspoint.MainActivity$1.onClick(MainActivity.java:25)
at android.view.View.performClick(View.java:5280)
at android.view.View$PerformClick.run(View.java:21239)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:234)
at android.app.ActivityThread.main(ActivityThread.java:5526)
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)
setText() is a overloaded method with two types: one that takes in a String, the other an int. The int here should be string resource ID. This is where your error is. In the code below you're using setText(int) but not passing a valid string resource ID.
int roll = RollDice(sidesChosen);
...
tv1.setText(roll);
Do setText(String.valueOf(roll) to convert it to a String first
EDIT after log post:
The cause of your error is that you're passing 0 to the nextInt() method. This might happen because you've never selected a RadioButton (sidesChosen is 0 by default) or that even after selecting a RadioButton, none of the cases of the switch is entered.
EDIT after second log post: (...)
Remove setContentView(tv1); This is used to attach a layout to an activity. Why are you using it here?
It seems, that you pass 0 to the Random.nextInt() method, which is not allowed.
java.lang.IllegalArgumentException: n <= 0: 0
at java.util.Random.nextInt(Random.java:182)
This happens, if none of your case branches is reached. So it seems, there is something wrong with how you handle the radio button clicks.

Categories

Resources