App crashes when backspace key is pressed - android

I am trying to learn java while building an android app. I have a points calculator without a button it uses a textchange listener to calculate the total. When backspace key is pressed and the box has null it crashes. I tried validating using the code below (only validated on field to begin with). But it does not work. Any help would be greatly appreciated.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wwcalc);
etFat = (EditText)findViewById(R.id.editTextFat);
etFiber = (EditText)findViewById(R.id.editTextFiber);
etProtein = (EditText)findViewById(R.id.editTextProtein);
etCarbs = (EditText)findViewById(R.id.editTextCarbs);
tvTotal = (TextView)findViewById(R.id.textViewPoints);
TextWatcher watcher = new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
if(isEmpty(etFat) == false){
intFat = Integer.parseInt(etFat.getText().toString());
}
else{
etFat.setText("0");
etFat.hasFocus();
return;
}
intProtein = Integer.parseInt(etProtein.getText().toString());
intFiber = Integer.parseInt(etFiber.getText().toString());
intCarbs = Integer.parseInt(etCarbs.getText().toString());
calculate();
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
// TODO Auto-generated method stub
}
};
etFat.addTextChangedListener(watcher);
etProtein.addTextChangedListener(watcher);
etFiber.addTextChangedListener(watcher);
etCarbs.addTextChangedListener(watcher);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_wwcalc, menu);
return true;
}
public void calculate(){
//intTot = intFat + intCarbs + intFiber + intProtein;
intTot = (int) Math.ceil((intFat * (4/35)) + (intCarbs * (4/36.84)) - (intFiber* (4/50))+ (intProtein * (4/43.75)) ) ;
tvTotal.setText(Integer.toString(intTot));
}
private boolean isEmpty(EditText etText)
{
if(etText.getText().toString().trim().length() > 0 || etText.getText().toString().trim() != null)
return false;
else
return true;
}
}
Thanks for the help all. I got it working not sure if it is the best solution if anyone thinks there is a better way let me know. The try catch as suggested by conor catches the exception, then just insert a 0 set focus and select the 0
try {
intFat = Integer.parseInt(etFat.getText().toString());
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
etFat.setText("0");
etFat.hasFocus();
etFat.selectAll();
}

Without seeing the stacktrace it is hard to know but i'm going to make a stab it anyway.
The following piece of your isEmpty() function is allowing false to be returned when the box could still be emtpy.
etText.getText().toString().trim() != null
This means that when you press backspace and clear the field it is empty but your function says it's not. Then the kicker, when your app thinks the field is not empty it tried to parse the contents for an integer value (which is not present). This attempt at parsing throws an exception and crashes your app.
I expect the stacktrace to show the app crashing at this line
intFat = Integer.parseInt(etFat.getText().toString());
It's worth noting that you should always surround calls like Integer.parseInt() with a try, catch block.
Hope that helps.

The exception should be caused by Integer.parseInt,
intFat = Integer.parseInt(etFat.getText().toString());
ntProtein = Integer.parseInt(etProtein.getText().toString());
intFiber = Integer.parseInt(etFiber.getText().toString());
intCarbs = Integer.parseInt(etCarbs.getText().toString());
If you pass string with spaces to parseInt, NumberFormatException will be thrown, you need to trim the text, and then set them, such as,
intFat = Integer.parseInt(etFat.getText().toString().trim());

try this
When backspace is pressed and a field is changed from say "0" to--> "" the operation that is supposed to convert the value to a double fails and crashed my application. "holder.mChoiceRNK"is the " EditView" reference " . If we look at what happens onAfterTextChanged we can set in a default value and then do a select all. The default value of "0" will not cause an error.
Cheers
And happy programming.
holder.mChoiceRNK.doAfterTextChanged {
Log.d(mTAG70, "130xxx 131 Pre Error")
if (holder.mChoiceRNK.text.toString() == "") {
holder.mChoiceRNK.setText("0") // new value if the backspace is pressed to create ""
holder.mChoiceRNK.selectAll()
} else{
Log.d(mTAG70, "130xxx 133 Past Error--> ${holder.mChoiceRNK.text}")
myRNKvotingArray[position].mRNK = holder.mChoiceRNK.text.toString().toDouble()
}}
Alternate solution:
holder.mChoiceRNK.doAfterTextChanged {
try {
myRNKvotingArray[position].mRNK =holder.mChoiceRNK.text.toString().toDouble()
} catch (err:Exception) {
holder.mChoiceRNK.setText("0")
holder.mChoiceRNK.selectAll()
}}

Related

EditText.setText()/getText() appears to be too slow to be used in TextWatcher

I have a TextWatcher that adds a dollar sign in front of an EditText value (it's a price field). Everything works fine except that if you type two first digits fast enough, the second digit won't appear. Once you past the first two digits it's all fine. If you type them slowly (almost a second in between) it also works fine.
Here is the TextWatcher code I am using:
#AfterTextChange(R.id.add_itemPrice) // android annotations way
void addDollar(Editable e) {
if (priceFieldBeingModified) {
return;
}
if (!e.toString().startsWith(CURRENCY_SYMB)) {
priceFieldBeingModified = true;
String newValue = CURRENCY_SYMB + e;
priceField.setText(newValue);
if (priceField.getSelectionStart() == 0) {
// move the cursor to the end
priceField.setSelection(priceField.getText().length());
}
priceFieldBeingModified = false;
}
}
priceField EditText has fixed layout_width/layout_height (in dp). From what I can gather, setText()/getText() are just too expensive but I don't know how to avoid them in this case.
priceField.getText().insert(0, CURRENCY_SYMB) doesn't do anything for some reason.
EDIT:
Looks like the problem only happens on Android 4.3 (or an Xperia Z phone). Tried a 4.1 phone - works like a charm.
Any suggestions would be appreciated, I am out of ideas with this one!
This is working fine for me:
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
if(s.toString().equalsIgnoreCase(""))
{
}
else if (!s.toString().startsWith("$")) {
priceFieldBeingModified = true;
String newValue = "$" + s;
e.setText(newValue);
if (e.getSelectionStart() == 0) {
// move the cursor to the end
e.setSelection(e.getText().length());
}
priceFieldBeingModified = false;
}
It checks if string is not null and it doesn't start with "$", then it adds "$" at start and moves cursor to end.

User input shouldn't exceed a particular number entered in edittext in android

Am developing a hymn app in android, is there a way to let users know that the number they have entered cannot be found in the database, thus the hymn index they entered the hymn is not up to that number immediately the entered it in the edit text.
This is a section of the code
android:ems="10"
android:inputType="number"
android:maxLength="3"`
Restricting length of the EditText could work if your value is inside [-99;999].
Anyway you should read and then validate the number.
EditText.
a. If you have a button (user enters hymn number and clicks a button to find), then add something like this in your onClick method:
Editable e = yourEditText.getText();
String hymnNumberInString = "";
if (e != null) s = hymnNumberInString.toString();
if (hymnNumber.isEmpty()) showEmptyAlert(); //show alert that string is empty;
try {
Integer hymnNumber = Integer.valueOf(s);
if (!findHymn(hymnNumber)) {//here is a search
showErrorMessage();
}
} catch (NumberFormatException e) {
e.printStackTrace();
showErrorMessage();
}
b. If you do not have a button, you can add a TextWatcher and show error if hymn number is exceeded:
yourEditText.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {}
#Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if (s != null && s.length() != 0) {
try {
Integer hymnNumber = Integer.valueOf(s);
if (findHymn(hymnNumber)) {
//everything is ok, do what you want with it
// BUT!!! Remember that user might entered only 1 and is still entering!
// To ensure that user already entered (or maybe already entered) you can wait for 2 sec.
//E.g. by using someHandler.postDelayed(runnableWithThisCodeInside, 2000);
} else {
showErrorMessage();
}
} catch (NumberFormatException e) {
e.printStackTrace();
showErrorMessage();
}
}
}
});
c. You can use this nice library to simplify proccess of validation.
For predefined set of numbers you can use NumberPicker. This component takes a String array as input (via setDisplayedValues()) - so you can populate it with numbers/string from the database. And its editable (unless you restrict it) - so your user can still enter the number he wants.
is there a way to let users know that the number they have entered cannot be found in the database.
Yes you can do that,Considering you are using EditText to let user enter the number, get the text from there like below
EditText mEdit = (EditText)findViewById(R.id.edittext);
Integer number=Integer.valueOf(editText.getText.toString());
Now you have the number you can run a query on database table to match against the corresponding values, whether it exists in database or not.Something like this
int count= SELECT count(*) FROM tbl_user
WHERE name = ' + number + '
if(count>0){
Log.d("Count","Value exist in database");
}

Check blank space when clicking in a EditText

I have a customized EditText class, whats is happening is that there is a validation already for the field, checking it's length and doing trim.
But, the app is crashing because it is possible to click in the field and insert data after 1 space.
How can I validate when clicking, that user can not write his data? If he/she writes data with one space, the app crashes and I receive the following exception.
java.lang.IllegalArgumentException: Start position must be less than the actual text length
Thanks in advance.
Either you can trim but remember this wont restrict to enter white spaces by user, If you want to restrict white spaces then you need to add filter for your edit text. Adding filter let you restrict what ever character you want to avoid.
P.S - Check for adding filter on given link How do I use InputFilter to limit characters in an EditText in Android?
add "addTextChangedListener" to your EditText and then onTextChanged you can check for your validation. For example,
txtEdit.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
String str = s.toString();
if(str.length() > 0 && str.startsWith(" ")){
Log.v("","Cannot begin with space");
txtEdit.setText("");
}else{
Log.v("","Doesn't contain space, good to go!");
}
}
#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
}
});
Get the edit text first by this way:
EditText name=(EditText) findViewById(R.id.txt);
String txtEdit=txt.getEditableText().toString();
then check the text length validation by:
if(txtEdit.length() == 0) {
//your code for what you want to do.
}
trim the string that you get from edit text.
String str=edtext.getText().toString().trim();
if(str!=null && !str.equalsIgnoreCase("")))
{
//perform your operations.
}
else
{
//give error message.
}

Build.Model doesn't provide the right information?

I am fairly new to the whole android-development.
I am trying to set a different layout depending on the Modelname.
I am working with the android-eclipse SDK
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
final String model = Build.MODEL;
if(model == "sdk")
{
setContentView(R.layout.activity_test_one);
} else
{
setContentView(R.layout.activity_test_two);
}
Toast.makeText(getApplicationContext(), model, Toast.LENGTH_SHORT).show();
}
The Toast says that the modelname is "sdk", but the if statement isn't executed, as indeed the else-part is executed.
What could be the reason for that?
You cannot use the '==' operator on the String as it checks to see if the string object is the same, not its content. Use .equals(String) instead.
if ("sdk".equals(model) {
...
}

Why is that unreachable code?

I'm generating a question and answers of that randomly. And I want to generate new random arrays and answer options according to those when users chose the correct answer. But it says "unreachable code" when I add a boolean while loop... What is theproblem?
Thanks...
final boolean basadon = false;
while(basadon)
{
Random soru = new Random();
final int[] rastgele = new int[1];
for (int i=0; i<1; i++)
{
rastgele[i]= soru.nextInt(8);
}
ArrayList<Integer> cevap = new ArrayList<Integer>();
for (int k = 0; k <= 7; ++k)
{
cevap.add(k);
}
final Integer[] rastgele2 = new Integer[4];
if (rastgele[0]!=cevap.get(0))
{
rastgele2[0]=cevap.get(0);
}
else
{
rastgele2[0]=cevap.get(3);
}
if (rastgele[0]!=cevap.get(1))
{
rastgele2[1]=cevap.get(1);
}
else
{
rastgele2[1]=cevap.get(3);
}
if (rastgele[0]!=cevap.get(2))
{
rastgele2[2]=cevap.get(2);
}
else
{
rastgele2[2]=cevap.get(3);
}
rastgele2[3]=rastgele[0];
Collections.shuffle(Arrays.asList(rastgele2));
view.setText(countries.get(rastgele[0]));
cevap1.setBackgroundResource(heads[rastgele2[0]]);
cevap1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (rastgele[0]==rastgele2[0])
{
cevap1.setBackgroundResource(heads[8]);
countries.remove(rastgele[0]);
basadon=true;
}
else {
cevap1.setBackgroundResource(heads[9]);
}
}
});
cevap2.setBackgroundResource(heads[rastgele2[1]]);
cevap2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (rastgele2[1]==rastgele[0])
{
cevap2.setBackgroundResource(heads[8]);
countries.remove(rastgele[0]);
basadon=true;
}
else {
cevap2.setBackgroundResource(heads[9]);
}
}
});
cevap3.setBackgroundResource(heads[rastgele2[2]]);
cevap3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (rastgele2[2]==rastgele[0])
{
cevap3.setBackgroundResource(heads[8]);
countries.remove(rastgele[0]);
basadon=true;
}
else {
cevap3.setBackgroundResource(heads[9]);
}
}
});
cevap4.setBackgroundResource(heads[rastgele2[3]]);
cevap4.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (rastgele2[3]==rastgele[0])
{
cevap4.setBackgroundResource(heads[8]);
countries.remove(rastgele[0]);
basadon=true;
}
else {
cevap4.setBackgroundResource(heads[9]);
}
}
});
}
} }
Looks like you start with basedon value as false and later set it to true inside the loop.
So, Change
final boolean basedon = false
while (basedon) {
....
}
to
boolean basedon = false;
do {
....
} while (basedon);
while(basadon) is always false, so you never enter the loop. What you really mean is probably while(basadon==false). Also, don't declare basalon as final boolean because you want to modify its value later, and that will give error.
Why are you declaring all of those variables as final?
If bsadon for example needs to change from false to true, it can't be final. A final value is exactly that, a constant, it won't change.
Don't declare something as final unless you want it to keep the same value for the entire runtime of your program.
You are saying basadon is always "false", that's what final means, so the compiler is telling you you will never enter the while, since you need it to evaluate "true" to enter.
The expression between () in you while clause, needs to evaluate to true for the code to enter.
To your specific question which you have asked:
Why does the compiler give unreachable code warning
The answer is that since the condition in while loop is always false, there is no chance that the code in while loop will get executed. The warning is given to indicate that (given the current code situation) you have wasted your effort in typing that portion of code and it is guaranteed never to be executed. To rectify this, you can remove the final modifier from basedon and put a programming logic to set the value of basedon which will decide whether to enter the loop or not. If you want the loop to always run put while(true).
But I believe that what you wanted to ask was how to make the random question and answer generator. For that you'll have to post a bigger chunk of your code (It looks like you are trying to put a loop over a listener callback ?) and phrase your question to ask specific problems (possibly post a separate question).
It's probably complaining because basadon is known to be false and the body of the while loop cannot be reached. You can suppress the complaint by adding this annotation to the method:
#SuppressWarnings("unused")
You might also try removing the final modifier from the declaration of basadon. That might resolve the issue (but I'm not sure about that).
EDIT I finally noticed that you are trying to modify basadon directly from within your click listeners. That obviously won't work if basadon is final, yet you cannot access local variable unless it is final. I suggest you change basadon to be a (non-final) field of the enclosing class. Then all the warnings and errors should go away.

Categories

Resources