i am making a length converter which uses TextWatcher. the shortened code is
v1.addTextChangedListener(new TextWatcher() {
@Override
publi
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) {
}
}
}