i am making a length converter which uses TextWatcher. the shortened code is
v1.addTextChangedListener(new TextWatcher() {
@Override
publi
Do not do setText inside onTextChanged(),it is causing recursion.
You can try the following: Set a boolean variable when you do setText from inside the onTextChange(). This boolean variable will help to identify that onTextChange was called because text was change programmatically and not by the user,thus avoiding recursion
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(isTextChangedByUser){
//calculate and set different values only when user has changed values
editext.setText("programmatically setting the text,change the flag")
isTextChangedByUser=false;
}else{
//to avoid recursion
return;
}
}
Second time when onTextChanged
is called it will simply return since isTextChangeByUser
flag is false.In this manner we will avoid recursion.
Alternatively,to make the implementation more simple you can put a "calculate" button next to each editext.You will only start calculation when the user presses this button and not when text changes.
You are creating an infinite loop of Text Changes between v1 and v2.
Whenever you edit something in v1, it's TextWatcher
sets the text of v2 which in turn triggers the onTextChanged()
of your v2's TextWatcher
. Now, v2's TextWatcher
sets text of v1 (which triggers the onTextChanged()
of your v1 again). This is creating a never-ending loop and you are getting the StackOverflow exception.
You have to change the flow of your code.
EDIT: I am showing an example, how to get rid of the StackOverflow error for two EditText fields. You can follow the similar coding for as many EditTexts as you want.
First of all, you can extend the TextWatcher like this (This will help you to keep your code organized. And, you can use this same TextWatcher for all your EditTexts):
class MyInputWatcher implements TextWatcher {
private EditText et;
private MyInputWatcher(EditText editText) {
et = editText;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
switch (et.getId()) {
case R.id.editText1: {
v2.removeTextChangedListener(watcher2);
v2.setText(s);// set whatever text you want to set in editText2
v2.addTextChangedListener(watcher2);
//add the above 3 lines of code for other EditTexts, too (if any)
break;
}
case R.id.editText2: {
v1.removeTextChangedListener(watcher1);
v1.setText(s); // set whatever text you want to set in editText1
v1.addTextChangedListener(watcher1);
break;
}
}
}
@Override
public void afterTextChanged(Editable s) {
}
}
The trick is to remove the onTextChangeListeners before you call setText()
. And, then add them back after you are done with setting text.
Declare these member variables:
private EditText v1, v2;
private MyInputWatcher watcher1, watcher2;
Now, in the onCreate() method, implement this:
v1 = (EditText)findViewById(R.id.editText1);
v2 = (EditText)findViewById(R.id.editText2);
watcher1 = new MyInputWatcher(v1);
watcher2 = new MyInputWatcher(v2);
v1.addTextChangedListener(watcher1);
v2.addTextChangedListener(watcher2);
For your convenience, the whole Activity class looks like this:
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.EditText;
public class MainActivity extends ActionBarActivity {
EditText v1, v2;
private MyInputWatcher watcher1, watcher2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
v1 = (EditText)findViewById(R.id.editText1);
v2 = (EditText)findViewById(R.id.editText2);
watcher1 = new MyInputWatcher(v1);
watcher2 = new MyInputWatcher(v2);
v1.addTextChangedListener(watcher1);
v2.addTextChangedListener(watcher2);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
class MyInputWatcher implements TextWatcher {
private EditText et;
private MyInputWatcher(EditText editText) {
et = editText;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
switch (et.getId()) {
case R.id.editText1: {
v2.removeTextChangedListener(watcher2);
v2.setText(s);// set whatever text you want to set in editText2
v2.addTextChangedListener(watcher2);
break;
}
case R.id.editText2: {
v1.removeTextChangedListener(watcher1);
v1.setText(s); // set whatever text you want to set in editText1
v1.addTextChangedListener(watcher1);
break;
}
}
}
@Override
public void afterTextChanged(Editable s) {
}
}
}