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 classModelSale
.. Not
sure if you already did that or not.. anyways this class should have
fields, getters, & setters correspond to theEditTexts
fields which
we have (quantity
,discount
, &price
). And these fields should
be set in theonBindViewHoder()
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
usinggetAdapterPostion()
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
All Com.Android.Support Libraries Must Use the Exact Same Version
Convert Bitmap Array to Yuv (Ycbcr Nv21)
How to Run Countdowntimer in a Service in Android
Android: Disable Soft Keyboard at All Edittexts
Upload Video to Facebook in Android
Fragment Transaction Animation: Slide in and Slide Out
How to Auto-Start an Android Application
How to Create an Android Library Jar with Gradle Without Publicly Revealing Source Code
Custom Dialog on Android: How to Center Its Title
Android Studio - Creating Modules Without Copying Files
Android Displaymetrics Returns Incorrect Screen Size in Pixels on Ics
Android: How to Open Another App from My App
Get Listview Item Position on Button Click
Android: How to Center Title in Toolbar
Problem to Achieve Curved Animation
Android Asynctask Testing with Android Test Framework
Android Adb Stop Application Command Like "Force-Stop" for Non Rooted Device