How to Remove All Listeners Added with Addtextchangedlistener

Removing TextChangedListener then re-adding it

Everytime you will update (by eg calling set text) your editText the afterTextChanged will be called, so I think you should refrain from calling setText every time you are in afterTextChanged and only call it when something is really changing.

sth like this

if ( !myCurrencyString.equals(et.getText()))
{
et.setText(myCurrencyString);
}

How to remove recursion in EditText TextChangedListener?

I have solved it with a variable. Got idea from @njzk2

int checker = 0;
search_name.addTextChangedListener(new TextWatcher(){
public void afterTextChanged(Editable s) {
checker = 0;
}
public void beforeTextChanged(CharSequence s, int start, int count, int after){}
public void onTextChanged(CharSequence s, int start, int before, int count){
if(checker!=1)
{
checker = 1;
search_name.setText(s.toString().replace("something", "s**ething"));
}
}
});

addTextChangedListener() fired multiple times and for all edittext fields in listview

zgc7009 is right in that you are not approaching the getView method correctly. Although you aren't wrong with how you are inflating the view. The problem I suspect is that there is no guarantee how many times getView is called there is an arbitrary number of TextWatcher listeners being added to the EditText. At first I thought you could only add one TextWatcher listener to an EditText, but as it turns out you can add many. This is the source for the addTextChangedListener method:

public void addTextChangedListener(TextWatcher watcher) {
if (mListeners == null) {
mListeners = new ArrayList<TextWatcher>();
}
mListeners.add(watcher);
}

Anyways. getView is being called mutliple times and adding more and more listeners. But there is no way for you to know how many times this is going to be. You need to associate the listeners with the data or someother way. This way you can check if you should add the listener. So something like the following:

if(currentListData.hasListener) { // Just an example. You define the logic or how you want to store the TextWatcher listener
userAnswer.addTextChangedListener(new TextWatcher() {
//le code
}
}

I'm not gonna write the code for you of course. But thats how to go about fixing it.

EDIT

Actually after thinking about it more you shouldn't even create more listeners than necessary. Add the listener when you inflate the view.

  if (convertView == null) {

LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.list_item, parent, false);
EditText userAnswer = (EditText) convertView.findViewById(R.id.userAnswer);
userAnswer.addTextChangedListener(new TextWatcher() {
//le code
@Override
public void afterTextChanged(Editable s) {
//Figure out the best way to get the current position.
}
}
}

Recyclerview with more than one views, Removing of addTextChangedListener() not working

But when I am inserting more than one views in recyclerview. Changing of any rows EditText's value except the current inserted views calling the listener itself again and again.

Well, the main issue of listener replication over and over again, that theses listeners exist in onBindViewHolder() as this method gets called every time a RecyclerView row is going to be displayed/recycled/changed/inserted on the screen; and that apparently happened whenever you added new items.

So, the possible way is to register these listeners somewhere else that going to be called once, or whenever you want to; i.e. not every time the rows are recycled.

You can do that in the ViewHolder constructor to the EditText's themselves.

Challenge: how can we know which EditText that the user modified? .. As if some EditText is modified and you recycled the views (i.e. scrolled up/down the list), you will see the value is messed up in multiple rows.

This can be solved by:

  • Tracking the EditText values in your model class ModelSale.. Not
    sure if you already did that or not.. anyways this class should have
    fields, getters, & setters correspond to the EditTexts fields which
    we have (quantity, discount, & price). And these fields should
    be set in the onBindViewHoder() to get the saved values whenever
    the rows are recycled.
    @Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
ModelSale sale = modelSaleList.get(position);

// ...... rest of your code

holder.unregisterTextWatcher();

holder.inputSaleQuantity.setText(sale.getQuantatiy());
holder.inputSaleDiscount.setText(sale.getDiscount());
holder.inputSalePrice.setText(sale.getPrice());

holder.registerTextWatchers();

//End on create method
}
  • Getting the current item in the ViewHolder using getAdapterPostion()

And this approach requires to move all the watchers, fields, & methods that are related to EditText watchers from the RecyclerViewAdapter to the ViewHolder

And every time before changing these EditTexts fields, you need to unregsiter the text Watchers.

And here's the adapter only with those modifications in order to be compact.

public class AdapterSaleEditable extends RecyclerView.Adapter<AdapterSaleEditable.ViewHolder> {

// ... your code

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
ModelSale sale = modelSaleList.get(position);

// ...... rest of your code

holder.unregisterTextWatcher();

holder.inputSaleQuantity.setText(sale.getQuantatiy());
holder.inputSaleDiscount.setText(sale.getDiscount());
holder.inputSalePrice.setText(sale.getPrice());

holder.registerTextWatchers();

//End on create method
}

public class ViewHolder extends RecyclerView.ViewHolder {
private TextView tvProductName, tvProductSize, tvProductCategory, tvSaleTime, tvProductPrice, tvProductBrand, tvProductManufacture, tvProductExpire, tvCount;
private EditText inputSaleQuantity, inputSaleDiscount, inputSalePrice, inputTotalPrice;
private CardView cvSell;

private TextWatcher quantityWatcher;
private TextWatcher priceWatcher;
private TextWatcher discountWatcher;

private void registerTextWatchers() {
Log.d("SocialCodia", "Registring Listener");
inputSaleQuantity.addTextChangedListener(quantityWatcher);
inputSalePrice.addTextChangedListener(priceWatcher);
inputSaleDiscount.addTextChangedListener(discountWatcher);
}

private void unregisterTextWatcher() {
Log.d("SocialCodia", "UnRegistring Listener");
inputSaleQuantity.removeTextChangedListener(quantityWatcher);
inputSalePrice.removeTextChangedListener(priceWatcher);
inputSaleDiscount.removeTextChangedListener(discountWatcher);
}

private void priceEvent() {
Log.d("SocialCodia", "PriceEvent Method Called");
unregisterTextWatcher();
int totalPrice = Integer.parseInt(inputTotalPrice.getText().toString().trim());
String sellPriceString = inputSalePrice.getText().toString().trim();
if (sellPriceString.trim().length() > 0) {
int sellPrice = Integer.parseInt(inputSalePrice.getText().toString().trim());
int discount = percentage(sellPrice, totalPrice);
inputSaleDiscount.setText(String.valueOf(discount));
} else {
inputSaleDiscount.setText(String.valueOf(100));
}
registerTextWatchers();
}

private void quantityEvent() {
Log.d("SocialCodia", "quantityEvent Method Called");
unregisterTextWatcher();
String quan = inputSaleQuantity.getText().toString().trim();
String per = inputSaleDiscount.getText().toString().trim();
int quantity;
int percentage;
if (quan == null || quan.length() < 1 || quan.isEmpty())
quantity = 1;
else
quantity = Integer.parseInt(quan);
if (per == null || per.length() < 1)
percentage = 0;
else
percentage = Integer.parseInt(per);
int price = Integer.parseInt(tvProductPrice.getText().toString());
int finalPrice = price * quantity;
inputTotalPrice.setText(String.valueOf(finalPrice));
int salePrice = percentageDec(finalPrice, percentage);
inputSalePrice.setText(String.valueOf(salePrice));
registerTextWatchers();
}

private void discountInputEvent() {
Log.d("SocialCodia", "discountInputEvent Method Called");
unregisterTextWatcher();
int totalPrice = Integer.parseInt(inputTotalPrice.getText().toString().trim());
String per = inputSaleDiscount.getText().toString().trim();
int percentage;
if (per == null || per.length() < 1)
percentage = 0;
else
percentage = Integer.parseInt(per);
int price = percentageDec(totalPrice, percentage);
inputSalePrice.setText(String.valueOf(price));
registerTextWatchers();
}

private int percentage(int partialValue, int totalValue) {
Log.d("SocialCodia", "percentage Method Called");
Double partial = (double) partialValue;
Double total = (double) totalValue;
Double per = (100 * partial) / total;
Double p = 100 - per;
return p.intValue();
}

private int percentageDec(int totalValue, int per) {
Log.d("SocialCodia", "percentageDec Method Called");
if (per == 0 || String.valueOf(per).length() < 0)
return totalValue;
else {
Double total = (double) totalValue;
Double perc = (double) per;
Double price = (total - ((perc / 100) * total));
Integer p = price.intValue();
return p;
}
}

public ViewHolder(@NonNull View itemView) {
super(itemView);

// Rest of your code

// Text Watchers

quantityWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

}

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

}

@Override
public void afterTextChanged(Editable editable) {
Log.d("SocialCodia", "afterTextChanged: quantityWatcher Event Listener Called");
quantityEvent();
}
};

priceWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

}

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

}

@Override
public void afterTextChanged(Editable editable) {
Log.d("SocialCodia", "afterTextChanged: priceWatcher Event Listener Called");
priceEvent();
}
};

discountWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

}

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

}

@Override
public void afterTextChanged(Editable editable) {
Log.d("SocialCodia", "afterTextChanged: discountWatcher Event Listener Called");
discountInputEvent();
}
};

registerTextWatchers();

}
}
}

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
}
}
});


Related Topics



Leave a reply



Submit