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!
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();
}
}
}
I have successfully populated my recycleview from mysql database and I want to implement search filter on it. I have seen some examples and tried to implement it. I know i'm close but cant get it properly to work.
My current progress is when I try to search something the whole recycle view goes blank and nothing happens after that.
Here are my java code:
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getHotelDetails();
mylearningAdapters1 = new ArrayList<>();
recyclerView = (RecyclerView) findViewById(R.id.reviews_list);
recyclerView.setHasFixedSize(true);
recyclerViewlayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(recyclerViewlayoutManager);
inputSearch = (EditText)findViewById(R.id.searchBar);
inputSearch.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable s) {
// filter your list from your input
filter(s.toString());
//you can use runnable postDelayed like 500 ms to delay search text
}
});
}
void filter(String text){
List<MyHotelReviewAdapter> temp = new ArrayList();
for(MyHotelReviewAdapter d: mylearningAdapters){
//or use .equal(text) with you want equal match
//use .toLowerCase() for better matches
if(d.getHotel_user().contains(text)){
temp.add(d);
}
}
//update recyclerview
RecyclerViewMyHotelReviewAdapter rc = new RecyclerViewMyHotelReviewAdapter(mylearningAdapters);
rc.updateList(temp);
}
Here is my Recycleview adapter class code:
RecyclerViewMyHotelReviewAdapter.java
public class RecyclerViewMyHotelReviewAdapter extends RecyclerView.Adapter<RecyclerViewMyHotelReviewAdapter.LearningHolder> {
static Context context;
public static List<MyHotelReviewAdapter> mylearningAdapters;
public RecyclerViewMyHotelReviewAdapter(List<MyHotelReviewAdapter> mylearningAdapters, Context context){
super();
this.mylearningAdapters = mylearningAdapters;
this.context = context;
}
public RecyclerViewMyHotelReviewAdapter(List<MyHotelReviewAdapter> mylearningAdapters) {
}
#Override
public RecyclerViewMyHotelReviewAdapter.LearningHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.show_hotel_details, parent, false);
LearningHolder learningHolder = new LearningHolder(view);
//RecyclerViewModuleAdapter.ModuleHolder moduleHolder = new RecyclerViewModuleAdapter.ModuleHolder(view);
return learningHolder;
}
#SuppressLint("NewApi")
#Override
public void onBindViewHolder(RecyclerViewMyHotelReviewAdapter.LearningHolder holder, int position) {
final MyHotelReviewAdapter mylearningAdapter1 = mylearningAdapters.get(position);
int t = 4;
String a = mylearningAdapter1.getHotel_People();
int c = t + Integer.parseInt(a);
//Toast.makeText(context, ""+c, Toast.LENGTH_SHORT).show();
holder.hotel_user.setText(mylearningAdapter1.getHotel_user());
holder.hotel_dateIn.setText(mylearningAdapter1.getHotel_CheckIn());
holder.hotel_dateOut.setText(mylearningAdapter1.getHotel_CheckOut());
holder.total.setText(String.valueOf("Guests: "+c));
holder.htlName.setText(mylearningAdapter1.getHotel_name());
holder.id.setText(mylearningAdapter1.getHotel_id());
//holder.english_d.setText(mylearningAdapter1.getEnglish());
}
public void updateList(List<MyHotelReviewAdapter> list){
mylearningAdapters = list;
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return mylearningAdapters.size();
}
public class LearningHolder extends RecyclerView.ViewHolder {
String deleteBooking = "http://site2test.in/OxygenClub/mobileapp/delete_booking_careTaker.php";
AppCompatTextView hotel_user, hotel_dateIn, hotel_dateOut, htlName, total, id;
Button checkIn, checkOut;
public LearningHolder(View itemView) {
super(itemView);
hotel_user = (AppCompatTextView)itemView.findViewById(R.id.name);
hotel_dateIn = (AppCompatTextView)itemView.findViewById(R.id.checkin);
hotel_dateOut = (AppCompatTextView)itemView.findViewById(R.id.checkout);
htlName = (AppCompatTextView)itemView.findViewById(R.id.hotelName);
total = (AppCompatTextView)itemView.findViewById(R.id.totalPeople);
id = (AppCompatTextView)itemView.findViewById(R.id.hotelId);
}
}
}...
My DataHolder class.
public class MyHotelReviewAdapter {
public String Hotel_People;
public String Hotel_CheckIn;
public String Hotel_CheckOut;
public String Hotel_User;
public String Hotel_Name;
public String Hotel_Id;
public String getHotel_CheckIn() {
return this.Hotel_CheckIn;
}
public void setHotel_CheckIn(String hotel_checkIn) {
this.Hotel_CheckIn = hotel_checkIn;
}
public String getHotel_CheckOut() {
return this.Hotel_CheckOut;
}
public void setHotel_CheckOut(String hotel_checkOut) {
this.Hotel_CheckOut = hotel_checkOut;
}
public String getHotel_People() {
return this.Hotel_People;
}
public void setHotel_People(String hotel_people) {
this.Hotel_People = hotel_people;
}
public String getHotel_user() {
return this.Hotel_User;
}
public void setHotel_user(String hotel_user) {
this.Hotel_User = hotel_user;
}
public String getHotel_name(){
return this.Hotel_Name;
}
public void setHotel_name(String hotel_name){
this.Hotel_Name = hotel_name;
}
public String getHotel_id(){
return this.Hotel_Id;
}
public void setHotel_id(String hotel_id){
this.Hotel_Id = hotel_id;
}
}
I want to search my data by Hotel_user. I have coded the value of getHotel_user in filter function.
After declaring and creating the textWatcher object, I would like to disable the send button and set it to gray if the chatText (edit text) is empty
I think it's a problem of ranking. Please help.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
list = (ListView)findViewById(R.id.listView);
list.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
chatText = (EditText)findViewById(R.id.editText);
//chatText.setOnKeyListener(this);
me = true;
send = (Button)findViewById(R.id.button);
change = (Button)findViewById(R.id.button2);
list.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
adp = new TheAdapter(getApplicationContext(),R.layout.chat);
list.setAdapter(adp);
chatText.addTextChangedListener(textWatcher);
checkFieldsForEmptyValues();
send.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
envoyer();
}
});
change.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
me = !me;
if (!me) {
change.setText(R.string.sender2);
} else {
change.setText(R.string.sender);
}
}
});
}
public void envoyer(){
adp.add(new messages(me, chatText.getText().toString()));
chatText.setText("");
}
private void checkFieldsForEmptyValues(){
String s1 = chatText.getText().toString();
if (s1.length() < 0 ) {
send.setEnabled(false);
} else {
send.setEnabled(true);
send.setBackgroundColor(Color.BLUE);
//send.setBackgroundColor((getResources().getColor(R.color.blue)));
}
}
In the onTextChanged is where you would check to see if the text field is empty:
chatText.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.length() > 0) { //enable}
else if (s.length() == 0 { //disable }
In your code, you have if (s1.length() < 0 ) which I don't think will ever be true because the text size will never be less than 0.
// Disable on init
send.setEnabled(false);
// add text changer
chatText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Enable when input is != null and not empty. You can check string lenght too
send.setEnabled(s != null && !s.toString().isEmpty());
}
#Override
public void afterTextChanged(Editable s) {
}
});
disable button before and add textwatch. You can also check if edittext value is not empty or verify string length.
I hope it will help you
I have this adapter
public class BookcaseAdapter extends SectionableAdapter implements
View.OnClickListener {
private Activity activity;
private Map<String, List<Sponsor>> mSponsorMap;
public BookcaseAdapter(Activity activity, LayoutInflater inflater,
int rowLayoutID, int headerID, int itemHolderID, int resizeMode, Map<String, List<Sponsor>> sponsorMap) {
super(inflater, rowLayoutID, headerID, itemHolderID, resizeMode);
this.activity = activity;
mSponsorMap = sponsorMap;
}
#Override
public Object getItem(int position) {
for (int i = 0; i < mSponsorMap.size(); ++i) {
if (position < mSponsorMap.get(i).size()) {
return mSponsorMap.get(i).get(position);
}
position -= mSponsorMap.get(i).size();
}
// This will never happen.
return null;
}
#Override
protected int getDataCount() {
int total = 0;
for (int i = 0; i < mSponsorMap.size(); ++i) {
total += mSponsorMap.get(i).size();
}
return total;
}
#Override
protected int getSectionsCount() {
return mSponsorMap.size();
}
#Override
protected int getCountInSection(int index) {
return mSponsorMap.get(index).size();
}
#Override
protected int getTypeFor(int position) {
int runningTotal = 0;
int i = 0;
for (i = 0; i < mSponsorMap.size(); ++i) {
int sectionCount = mSponsorMap.get(i).size();
if (position < runningTotal + sectionCount)
return i;
runningTotal += sectionCount;
}
// This will never happen.
return -1;
}
#Override
protected String getHeaderForSection(int section) {
List<List<Sponsor>> l = new ArrayList<List<Sponsor>>(mSponsorMap.values());
String string = l.get(section).get(0).getCountry_name();
return string;
}
#Override
protected void bindView(View convertView, int position) {
String title = (String) getItem(position);
ImageView label = (ImageView) convertView
.findViewById(R.id.bookItem_title);
label.setImageResource(R.drawable.place_holder_thumb);
convertView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Intent i = new Intent(Intent.ACTION_SEARCH);
ImageView label = (ImageView) v.findViewById(R.id.bookItem_title);
// String text = label.getText().toString();
// i.putExtra(SearchManager.QUERY, text);
// activity.startActivity(i);
label.setImageResource(R.drawable.place_holder_thumb);
}
}
When from my activity I call this adapter and pass to sponsorMap values it's getting null and I have null pointer exceptoin.
I debug it found that when I call adapter and it's reach to super(inflater, rowLayoutID, headerID, itemHolderID, resizeMode); and after that called
#Override
protected int getSectionsCount() {
return mSponsorMap.size();
}
I'am sure that mSponsorMap=sponsormap not called ever. Why this is happening?
It will be called but later, the exception you got when the the super constructor is invoked prevent your constructor code from being actually reached.
Just add an NPE guard in your overriden method:
#Override
protected int getSectionsCount() {
return mSponsorMap == null ? 0 : mSponsorMap.size();
}
Alternatively you could also initialize your mSponsorMap to an empty Map:
private Map<String, List<Sponsor>> mSponsorMap = Collections.emptyMap();
And then in your constructor do:
mSponsorMap.putAll(sponsorMap);
Cheers,
I am trying to create an image viewer which can load images from given URLs.The code below implement the User Interface.
My intention is to let user Zoom the image and move to next image with a Swipe event.But the problem is that when i zoom and then swipe , instead of showing the remaining portion , it moves to the next image.
I tried using requestDisallowInterceptTouchEvent in TouchImageView's(https://github.com/MikeOrtiz/TouchImageView) onTouchListener .After this the remaining portion could show but now i cannot go to the next page. I was wondering how this can be achieved as the event can only go to either TouchView or PageAdapter
public class PageActivity extends Activity {
private int numPages = 33;
private TouchImageView[] imageViews = new TouchImageView[numPages];
private String URL = "http://www.smbc-comics.com/comics/200905";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewPager viewPager = new ViewPager(this);
for (int i = 0; i < numPages; i++) {
imageViews[i] = new TouchImageView(this);
imageViews[i].setBackgroundResource(R.drawable.banke);
imageViews[i].setMaxZoom(4f);
}
setContentView(viewPager);
ImagePagerAdapter adapter = new ImagePagerAdapter();
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(2);
}
#SuppressWarnings("unused")
private class ImagePagerAdapter extends PagerAdapter {
#Override
public int getCount() {
return numPages;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((TouchImageView) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Context context = PageActivity.this;
String pageURL = URL;
if (imageViews[position].getDrawable() == null) {
ImageFetcher imagefetcher = new ImageFetcher();
imagefetcher.execute(
pageURL + String.format("%02d", position+1) + ".gif",
String.valueOf(position));
}
((ViewPager) container).addView(imageViews[position], 0);
return imageViews[position];
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((TouchImageView) object);
imageViews[position].setImageDrawable(null);
}
}
public class ImageFetcher extends AsyncTask<String, Integer, Drawable> {
int fillthisPos;
public Drawable doInBackground(String... urls) {
try {
InputStream is = (InputStream) new URL(urls[0]).getContent();
fillthisPos = Integer.parseInt(urls[1]);
Drawable d = Drawable.createFromStream(is, "src name");
return d;
} catch (Exception e) {
return null;
}
}
#Override
protected void onPostExecute(Drawable result) {
super.onPostExecute(result);
imageViews[fillthisPos].setImageDrawable(result);
result = null;
}
}
}
You can add following code in TouchImageView class:
public boolean isZoomed () {
return (normalizedScale > minScale);
}
private void onSwipeEvent(MotionEvent event) {
boolean zoomed = this.isZoomed();
if (!zoomed && (swipeLen > 0)) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
swipeStartPos = (int) event.getRawX();
}
else if (event.getAction() == MotionEvent.ACTION_MOVE) {
int distance = ((int) event.getRawX()) - swipeStartPos;
int swipeVector = SWIPE_RIGHT;
if (distance < 0) swipeVector = SWIPE_LEFT;
if (Math.abs(distance) > swipeLen) {
onSwipeHandler.onSwipe(swipeVector);
swipeStartPos = (int) event.getRawX();
this.setScaleX(1f);
}
else {
int swipeStDist = swipeLen - Math.round(((swipeLen / 100) * 50));
if (Math.abs(distance) > swipeStDist) {
this.setScaleX(0.98f);
}
}
}
else if (event.getAction() == MotionEvent.ACTION_UP) {
swipeStartPos = (int) event.getRawX();
this.setScaleX(1f);
}
}
}
public static int SWIPE_LEFT = 0;
public static int SWIPE_RIGHT = 1;
public int swipeStartPos = 0;
public onSwipeListener onSwipeHandler = new onSwipeListener() {
public void onSwipe(int vector) {}
};
public static int swipeLen = 0;
public void setOnSwipeListener(onSwipeListener c, int swipeLength) {
onSwipeHandler = c;
swipeLen = swipeLength;
}
public interface onSwipeListener {
public void onSwipe(int vector);
}
And also in TouchImageView below line 636 add onSwipeEvent(event) like this:
......
setImageMatrix(matrix);
onSwipeEvent(event);
//
// indicate event was handled
//
return true;
...........
After this from you code you can add swipe event listener, like this:
imageView.setOnSwipeListener(new TouchImageView.onSwipeListener() {
#Override
public void onSwipe(int vector) {
if (vector == TouchImageView.SWIPE_LEFT) {
Log.d("swipe", "swipe left!");
}
else if (vector == TouchImageView.SWIPE_RIGHT) {
Log.d("swipe", "swipe right!");
}
}
}, 200); //length of swiping - 200 dip
This onSwipeListener ignore onswipe where image is zoomed+. It work for me.