How to Change the Edittext Text Without Triggering the Text Watcher

How can I change the EditText text without triggering the Text Watcher?

You could unregister the watcher, and then re-register it.

Alternatively, you could set a flag so that your watcher knows when you have just changed the text yourself (and therefore should ignore it).

Android - How to run full method before triggering TextWatcher?

just create a boolean as -

boolean BLOCK = false;

and

private void myMethod(String firstText, String secondText) {
BLOCK = true;
editText1.setText(firstText); //Watcher won't be triggered first time
BLOCK = false;
editText2.setText(secondText); //Watcher will be triggered now

}

now in onTextChange Method do as

void onTextChanged (CharSequence s, int start, int before, int count){
if(!BLOCK){
// your code
}

}

using setText() don't want to call textwatcher events?

You could unregister the watcher, and then re-register it.

To unregister the watcher use this code:

txt_qty.removeTextChangedListener(yourTextWatcher);

to re-register it use this code:

txt_qty.addTextChangedListener(yourTextWatcher);

Alternatively, you could set a flag so that your watcher knows when you have just changed the text yourself (and therefore should ignore it).

define one flag in your activity is:
boolean isSetInitialText = false;

and when you are calling txt_qty.settext(yourText) make isSetInitialText = true before calling set text,

And then update your watcher as:

txt_qty.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (isSetInitialText){
isSetInitialText = false;
} else{
// perform your operation
}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (isSetInitialText){
isSetInitialText = false;
} else{
// perform your operation
}
}

@Override
public void afterTextChanged(Editable s) {
if (isSetInitialText){
isSetInitialText = false;
} else{
// perform your operation
}
}
});

How can I avoid execution of onTextChanged in Android's EditText

The Source for AutoCompleteTextView shows that they set a boolean to say the text is being replaced by the block completion

         mBlockCompletion = true;
replaceText(convertSelectionToString(selectedItem));
mBlockCompletion = false;

This is as good a way as any to achieve what you want to do.
The TextWatcher then checks to to see if the setText has come via a completion and returns out of the method

 void doBeforeTextChanged() {
if (mBlockCompletion) return;

Adding and removing the TextWatcher will be more time consuming for the application

How to update the same EditText using TextWatcher?

The content of the TextView is uneditable on the onTextChanged event.

Instead, you need to handle the afterTextChanged event to be able to make changes to the text.

For more thorough explanation see: Android TextWatcher.afterTextChanged vs TextWatcher.onTextChanged


Note: Error onTextChanged

Obvioulsy, you are causing an endless loop by continuously changing the text on afterTextChanged event.

From the ref:

public abstract void afterTextChanged (Editable s)
This method is called to notify you that, somewhere within s, the text has been
changed. It is legitimate to make further changes to s from this
callback, but be careful not to get yourself into an infinite loop,
because any changes you make will cause this method to be called again
recursively. ...

  • Suggestion 1: if you can, check if the s is already what you want when the event is triggered.

    @Override
    public void afterTextChanged(Editable s)
    {
    if( !s.equalsIngoreCase("smth defined previously"))
    s = "smth defined previously";
    }
  • Suggestion 2: if you need to do more complex stuff (formatting,
    validation) you can maybe use a synchronized method like in this
    post.

Note 2 : Formatting the input as partially hidden with n stars till the last 4 chars ( ****four)

You can use something like this in suggestion 1:

    @Override
public void afterTextChanged(Editable s)
{
String sText = ET.getText().toString()

if( !isFormatted(sText))
s = format(sText);
}
bool isFormatted(String s)
{
//check if s is already formatted
}

string format(String s)
{
//format s & return
}

TextWatcher -related code works well only with one EditView

It took me quite some time in trial and error but I managed to make the code work in correct way.
@LalitFauzdar - thank you very much for helping me find out a part of the EditText - related solution.:

@Override
public void onTextChanged(CharSequence charSequence, int start, int before, int i2) {
mPetHasChanged = start!= before;
}

The other part turned out to be listening to delete key strokes when the user modifies the data.
Then I also had to notify the user of pending changes, if he modified his selection in the spinner,showing the pet's gender in my activity.
https://stackoverflow.com/a/24399683/10632237 this answer is the one that gave me idea how to listen for "real" changes, which the user made to the spinner.
Here are the parts of the code,related to the initial question:

 /**
* Allows user to create a new pet or edit an existing one.
*/
public class EditorActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>, TextWatcher, View.OnKeyListener, View.OnTouchListener {

/**
* EditText field to enter the pet's name
*/
private EditText mNameEditText;

/**
* EditText field to enter the pet's breed
*/
private EditText mBreedEditText;

/**
* EditText field to enter the pet's weight
*/
private EditText mWeightEditText;

/**
* EditText field to enter the pet's gender
*/
private Spinner mGenderSpinner;

/**
* Gender of the pet. The possible values are:
* 0 for unknown gender, 1 for male, 2 for female.
*/
public static int mGender;

public static String mPetName;

public static String mPetBreed;

public static String mPetWeight;

private static ArrayAdapter mGenderSpinnerAdapter;

private static Uri mSinglePetUri;
/**we will show warning dialog to the user,if the below variable is true*/
private boolean mPetHasChanged;
/**This flag turns to true if the spinner was actually touched by the user */
private boolean spinnerActivated;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_editor);
// checks if we are about to edit the information about an existing pet or add
// a new pet record , adjusts the activity title accordingly and initializes/
// activates Loader only if we are updating an existing pet
mSinglePetUri = getIntent().getData();
if (mSinglePetUri != null) {
setTitle(R.string.edit_pet_activity_title);
getSupportLoaderManager().initLoader(0, null, this);
} else {
setTitle(getString(R.string.add_a_pet_activity_title));

}
// Find all relevant views that we will need to read user input from
mNameEditText = findViewById(R.id.edit_pet_name);
mBreedEditText = findViewById(R.id.edit_pet_breed);
mWeightEditText = findViewById(R.id.edit_pet_weight);
mGenderSpinner = findViewById(R.id.spinner_gender);
setupSpinner();
mNameEditText.addTextChangedListener(this);
mBreedEditText.addTextChangedListener(this);
mWeightEditText.addTextChangedListener(this);
mNameEditText.setOnKeyListener(this);
mBreedEditText.setOnKeyListener(this);
mWeightEditText.setOnKeyListener(this);
mGenderSpinner.setOnTouchListener(this);

}

/**
* Setup the dropdown spinner that allows the user to select the gender of the pet.
*/
private void setupSpinner() {
// Create adapter for spinner. The list options are from the String array it will use
// the spinner will use the default layout
mGenderSpinnerAdapter = ArrayAdapter.createFromResource(this,
R.array.array_gender_options, android.R.layout.simple_spinner_item);

// Specify dropdown layout style - simple list view with 1 item per line
mGenderSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line);

// Apply the adapter to the spinner
mGenderSpinner.setAdapter(mGenderSpinnerAdapter);

// attach listener to the spinner to handle user selection from the pet's gender list.
mGenderSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {

@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

String selection = (String) parent.getItemAtPosition(position);

if (selection.equals(getString(R.string.gender_male))) {
mGender = PetsEntry.PET_GENDER_MALE;

} else if (selection.equals(getString(R.string.gender_female))) {
mGender = PetsEntry.PET_GENDER_FEMALE;

} else {
mGender = PetsEntry.PET_GENDER_UNKNOWN;
}
// if the Spinner was not actually touched by the user, the
//spinnerActivated flag is
//false and the method is exited earlier as there was not actual selection
//change,
//made by the user.This manages the behaviour of onItemSelected ,where the
// method is
//called twice - once when the spinner is initialized and once again if
// the user changes
//selection.
if (!spinnerActivated){
return;
}
mPetHasChanged=true;

}

// Because onItemSelectedListener is an interface, onNothingSelected must be
// defined
@Override
public void onNothingSelected(AdapterView<?> parent) {
mGender = PetsEntry.PET_GENDER_UNKNOWN;
}
});
}
//more code between,unrelated to topic

@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

}
/**The logic in this method gets triggered if the user changes existing pet's data by
using
* any key except the delete one*/
@Override
public void onTextChanged(CharSequence charSequence, int start, int before, int count) {

if (start != before){
mPetHasChanged=true;
}

}

@Override
public void afterTextChanged(Editable editable) {

}
/** The logic in this method gets triggered if the user presses the delete button,
* while editing pet's data, so we won't miss any type of editing action*/

@Override
public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
if (keyCode== KeyEvent.KEYCODE_DEL){
mPetHasChanged=true;
}

return false;
}

/**This method checks if the spinner was actually touched by the user and turns the
* flag variable to true and based on the flag's value we trigger the further logic in
* {#onItemSelected}*/
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
spinnerActivated=true;
return false;
}
}

How can I change the EditText text without triggering the Text Watcher?

You could unregister the watcher, and then re-register it.

Alternatively, you could set a flag so that your watcher knows when you have just changed the text yourself (and therefore should ignore it).



Related Topics



Leave a reply



Submit