I am working on an android app where I am changing the some of EditText's Value programmatically on manually change of EditText's Value.
- When user change the quantity I am changing the total price & sale price value.
- When user change the sale price I am changing the discount value.
- When user change the discount I am changing the sale price value.
I have added a addTextChangedListener() on every EditText. But before that I have created TextWatcher object for each EditText's globally.
private TextWatcher quantityWatcher;
private TextWatcher priceWatcher;
private TextWatcher discountWatcher;
And define it onBindViewHolder() method, so whenever I want to remove or add a TextChangedListener() on it, I can do it easily.
Before changing the any EditText's values programmatically I am removing the addTextChangedListener() on every TextWatcher's objects by using removeTextChangedListener() to avoid calling the function by itself. After changing the value and registering back the listener on it.
For Quantity EditText
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(holder);
}
};
For Discount EditText.
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(holder);
}
};
For Sale Price EditText
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(holder);
}
};
The method which I am calling on change of EditText's values.
private void priceEvent(ViewHolder holder) {
Log.d("SocialCodia", "PriceEvent Method Called");
unregisterTextWatcher(holder);
int totalPrice = Integer.parseInt(holder.inputTotalPrice.getText().toString().trim());
String sellPriceString = holder.inputSalePrice.getText().toString().trim();
if (sellPriceString.trim().length()>0)
{
int sellPrice = Integer.parseInt(holder.inputSalePrice.getText().toString().trim());
int discount = percentage(sellPrice, totalPrice);
holder.inputSaleDiscount.setText(String.valueOf(discount));
}
else
{
holder.inputSaleDiscount.setText(String.valueOf(100));
}
registerTextWatchers(holder);
}
private void quantityEvent(ViewHolder holder)
{
Log.d("SocialCodia", "quantityEvent Method Called");
unregisterTextWatcher(holder);
String quan = holder.inputSaleQuantity.getText().toString().trim();
String per = holder.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(holder.tvProductPrice.getText().toString());
int finalPrice = price*quantity;
holder.inputTotalPrice.setText(String.valueOf(finalPrice));
int salePrice = percentageDec(finalPrice,percentage);
holder.inputSalePrice.setText(String.valueOf(salePrice));
registerTextWatchers(holder);
}
private void discountInputEvent(ViewHolder holder) {
Log.d("SocialCodia", "discountInputEvent Method Called");
unregisterTextWatcher(holder);
int totalPrice = Integer.parseInt(holder.inputTotalPrice.getText().toString().trim());
String per = holder.inputSaleDiscount.getText().toString().trim();
int percentage;
if (per==null || per.length()<1)
percentage = 0;
else
percentage = Integer.parseInt(per);
int price = percentageDec(totalPrice, percentage);
holder.inputSalePrice.setText(String.valueOf(price));
registerTextWatchers(holder);
}
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;
}
}
Every conditions, logic, or method are working fine. 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.
I have tried to figure out the exact issue but unable to do it.
My Adapter Class AdapterSaleEditable.java
public class AdapterSaleEditable extends RecyclerView.Adapter<AdapterSaleEditable.ViewHolder> {
private Context context;
private List<ModelSale> modelSaleList;
private String token;
private SharedPrefHandler sp;
private ModelUser user;
private boolean discountFlag = false;
private boolean priceEvenFlag = false;
private TextWatcher quantityWatcher;
private TextWatcher priceWatcher;
private TextWatcher discountWatcher;
public AdapterSaleEditable(Context context, List<ModelSale> modelSales) {
this.context = context;
this.modelSaleList = modelSales;
sp = SharedPrefHandler.getInstance(context);
user = sp.getUser();
token = user.getToken();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.row_sale_editable, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
ModelSale sale = modelSaleList.get(position);
int productId = sale.getProductId();
int saleId = sale.getSaleId();
String productCategory = sale.getProductCategory();
String productName = sale.getProductName();
String productSize = sale.getProductSize();
String productBrand = sale.getProductBrand();
int productPrice = sale.getProductPrice();
int productQuantity = sale.getProductQuantity();
String productManufacture = sale.getProductManufacture();
String productExpire = sale.getProductExpire();
String createdAt = sale.getCreatedAt();
holder.tvProductName.setText(productName);
holder.tvProductSize.setText("(" + productSize + ")");
holder.tvProductCategory.setText(productCategory);
holder.tvProductPrice.setText(String.valueOf(productPrice));
holder.inputTotalPrice.setText(String.valueOf(productPrice));
holder.inputSaleQuantity.setText(String.valueOf(1));
holder.inputSalePrice.setText(String.valueOf(productPrice));
holder.inputSaleDiscount.setText(String.valueOf(0));
holder.tvProductBrand.setText(productBrand);
holder.tvProductManufacture.setText(productManufacture);
holder.tvProductExpire.setText(productExpire);
holder.tvCount.setText(String.valueOf(position + 1));
holder.cvSell.setOnLongClickListener(view -> {
showDeleteAlert(holder, sale, position);
return true;
});
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(holder);
}
};
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(holder);
}
};
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(holder);
}
};
registerTextWatchers(holder);
//End on create method
}
private void registerTextWatchers(ViewHolder holder) {
Log.d("SocialCodia", "Registring Listener");
holder.inputSaleQuantity.addTextChangedListener(quantityWatcher);
holder.inputSalePrice.addTextChangedListener(priceWatcher);
holder.inputSaleDiscount.addTextChangedListener(discountWatcher);
}
private void unregisterTextWatcher(ViewHolder holder)
{
Log.d("SocialCodia", "UnRegistring Listener");
holder.inputSaleQuantity.removeTextChangedListener(quantityWatcher);
holder.inputSalePrice.removeTextChangedListener(priceWatcher);
holder.inputSaleDiscount.removeTextChangedListener(discountWatcher);
}
private void priceEvent(ViewHolder holder) {
Log.d("SocialCodia", "PriceEvent Method Called");
unregisterTextWatcher(holder);
int totalPrice = Integer.parseInt(holder.inputTotalPrice.getText().toString().trim());
String sellPriceString = holder.inputSalePrice.getText().toString().trim();
if (sellPriceString.trim().length()>0)
{
int sellPrice = Integer.parseInt(holder.inputSalePrice.getText().toString().trim());
int discount = percentage(sellPrice, totalPrice);
holder.inputSaleDiscount.setText(String.valueOf(discount));
}
else
{
holder.inputSaleDiscount.setText(String.valueOf(100));
}
registerTextWatchers(holder);
}
private void quantityEvent(ViewHolder holder)
{
Log.d("SocialCodia", "quantityEvent Method Called");
unregisterTextWatcher(holder);
String quan = holder.inputSaleQuantity.getText().toString().trim();
String per = holder.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(holder.tvProductPrice.getText().toString());
int finalPrice = price*quantity;
holder.inputTotalPrice.setText(String.valueOf(finalPrice));
int salePrice = percentageDec(finalPrice,percentage);
holder.inputSalePrice.setText(String.valueOf(salePrice));
registerTextWatchers(holder);
}
private void discountInputEvent(ViewHolder holder) {
Log.d("SocialCodia", "discountInputEvent Method Called");
unregisterTextWatcher(holder);
int totalPrice = Integer.parseInt(holder.inputTotalPrice.getText().toString().trim());
String per = holder.inputSaleDiscount.getText().toString().trim();
int percentage;
if (per==null || per.length()<1)
percentage = 0;
else
percentage = Integer.parseInt(per);
int price = percentageDec(totalPrice, percentage);
holder.inputSalePrice.setText(String.valueOf(price));
registerTextWatchers(holder);
}
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;
}
}
private void showDeleteAlert(ViewHolder holder, ModelSale sale, int position) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Are you sure want to delete?");
builder.setMessage("You are going to delete " + sale.getProductName() + ". The Sale Quantity of this product was " + sale.getSaleQuantity() + " and the total price was " + sale.getSalePrice());
builder.setPositiveButton("Delete", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
deleteSoldProduct(sale.getSaleId(), position);
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(context, "Deletion Canceled", Toast.LENGTH_SHORT).show();
}
});
builder.show();
}
private void deleteSoldProduct(int sellId, int position) {
Call<ResponseDefault> call = ApiClient.getInstance().getApi().deleteSoldProduct(sellId, token);
call.enqueue(new Callback<ResponseDefault>() {
@Override
public void onResponse(Call<ResponseDefault> call, Response<ResponseDefault> response) {
if (response.isSuccessful()) {
ResponseDefault responseDefault = response.body();
if (!responseDefault.isError()) {
TastyToast.makeText(context, responseDefault.getMessage(), Toast.LENGTH_SHORT, TastyToast.SUCCESS);
Helper.playSuccess();
Helper.playVibrate();
modelSaleList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, modelSaleList.size());
} else
TastyToast.makeText(context, responseDefault.getMessage(), Toast.LENGTH_SHORT, TastyToast.ERROR);
} else
Toast.makeText(context, "Request Isn't Success", Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<ResponseDefault> call, Throwable t) {
t.printStackTrace();
}
});
}
public void updateList(List<ModelSale> list) {
modelSaleList = list;
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return modelSaleList.size();
}
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;
public ViewHolder(@NonNull View itemView) {
super(itemView);
tvProductName = itemView.findViewById(R.id.tvProductName);
tvProductSize = itemView.findViewById(R.id.tvProductSize);
tvProductCategory = itemView.findViewById(R.id.tvProductCategory);
tvSaleTime = itemView.findViewById(R.id.tvSaleTime);
tvProductPrice = itemView.findViewById(R.id.tvProductPrice);
inputSaleQuantity = itemView.findViewById(R.id.inputSaleQuantity);
inputSaleDiscount = itemView.findViewById(R.id.inputSaleDiscount);
inputSalePrice = itemView.findViewById(R.id.inputSalePrice);
tvProductBrand = itemView.findViewById(R.id.tvProductBrand);
tvProductManufacture = itemView.findViewById(R.id.tvProductManufacture);
tvProductExpire = itemView.findViewById(R.id.tvProductExpire);
inputTotalPrice = itemView.findViewById(R.id.inputTotalPrice);
tvCount = itemView.findViewById(R.id.tvCount);
cvSell = itemView.findViewById(R.id.cvSell);
}
}
}
My Fragment. From Where I am setting the recyclerview. SellProductFragment.java
public class SellProductActivity extends AppCompatActivity {
private ImageView ivCloseDialog;
private RecyclerView recyclerView;
private EditText inputSearchProduct;
private static List<ModelProduct> modelProductList;
private AdapterProductSale adapterProductSale;
private int productId;
private ActionBar actionBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sell_product);
init();
actionBar = getSupportActionBar();
actionBar.setTitle("Sell Product");
setRecyclerView();
inputSearchProduct.addTextChangedListener(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) {
filter(editable.toString());
}
});
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_close,menu);
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int id = item.getItemId();
if (id==R.id.miClose)
{
onBackPressed();
}
return super.onOptionsItemSelected(item);
}
private void filter(String text)
{
List<ModelProduct> p = new ArrayList<>();
for(ModelProduct sale : modelProductList)
{
if (sale.getProductName().toLowerCase().trim().contains(text.toLowerCase()))
{
p.add(sale);
}
}
adapterProductSale.updateList(p);
}
private void setRecyclerView() {
LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
modelProductList = DbHandler.getModelProductList();
adapterProductSale = new AdapterProductSale(SellProductActivity.this, modelProductList);
recyclerView.setAdapter(adapterProductSale);
}
private void init() {
recyclerView = findViewById(R.id.rvProducts);
inputSearchProduct = findViewById(R.id.inputSearchProduct);
modelProductList = new ArrayList<>();
}
}
How can I solve the issue.
-Thanks for any help!

