I am struggling with a problem - trying to refresh search results after the RecyclerView item is removed.
Right now, when I have filtered items out and delete one of them, RecyclerView shows all other items again, without a search filter applied.
But how to implement search filter so, that it stays on even when RecyclerView list has changed?
This is how I load data in main activity:
private void loadData(final int ordernumber) {
orderLineViewModel.getAllUnCheckedSingleOrderLines(ordernumber).observe(this, new Observer<List<OrderLine>>() {
#Override
public void onChanged(List<OrderLine> orderLines) {
orderLineListAdapter.setOrderLines(orderLines);
}
});
}
This is my SearchView code in main activity:
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String s) {
orderLineListAdapter.getFilter().filter(s);
return false;
}
#Override
public boolean onQueryTextChange(String s) {
orderLineListAdapter.getFilter().filter(s);
return false;
}
});
This is my filter in RecyclerViewAdapter:
public void setOrderLines(List<OrderLine> orderLines) {
orderLineList = orderLines;
orderLineListFull = new ArrayList<>(orderLines);
notifyDataSetChanged();
}
#Override
public Filter getFilter() {
return orderFilter;
}
private Filter orderFilter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
List<OrderLine> filteredList = new ArrayList<>();
if (charSequence == null || charSequence.length() == 0){
filteredList.addAll(orderLineListFull);
}else {
String filterPattern = charSequence.toString().toLowerCase().trim();
for (OrderLine orderLine: orderLineListFull){
if (orderLine.getProductCode().toLowerCase().contains(filterPattern)){
filteredList.add(orderLine);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
orderLineList.clear();
orderLineList.addAll((List)filterResults.values);
notifyDataSetChanged();
}
};
Pressing checkbox in RecyclerView item:
#Override
public void onClick(View view) {
int position = getAdapterPosition();
OrderLine line = orderLineList.get(position);
switch (view.getId()) {
case R.id.foam_in_checkbox:
if (okCheckBox.isChecked()) {
line.setIsArrived(1);
orderLineViewModel.update(line);
orderLineList.remove(position);
notifyItemRemoved(position);
} else {
line.setIsArrived(0);
orderLineViewModel.update(line);
}
break;
}
}
Edit: Added whole RecyclerViewAdapter:
public class OrderLineListAdapter extends
RecyclerView.Adapter<OrderLineListAdapter.OrderLineViewHolder> implements Filterable {
private Context context;
private final LayoutInflater orderLineInflater;
private List<OrderLine> orderLineList;
private List<OrderLine> orderLineListFull;
private OrderLineViewModel orderLineViewModel;
public OrderLineListAdapter(Context context) {
this.context = context;
orderLineInflater = LayoutInflater.from(context);
orderLineViewModel = ViewModelProviders.of((FoamInActivity) context).get(OrderLineViewModel.class);
}
#NonNull
#Override
public OrderLineViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = orderLineInflater.inflate(R.layout.foam_in_single_line, parent, false);
return new OrderLineViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull OrderLineViewHolder orderLineViewHolder, int position) {
if (orderLineList != null) {
OrderLine current = orderLineList.get(position);
orderLineViewHolder.productCodeTextView.setText(current.getProductCode());
orderLineViewHolder.orderedQuantityTextView.setText(String.valueOf(current.getOrderedQuantity()));
orderLineViewHolder.okCheckBox.setOnCheckedChangeListener(null);
orderLineViewHolder.okCheckBox.setChecked(false);
} else {
orderLineViewHolder.productCodeTextView.setText(R.string.no_open_positions);
}
}
public void setOrderLines(List<OrderLine> orderLines) {
orderLineList = orderLines;
orderLineListFull = new ArrayList<>(orderLines);
notifyDataSetChanged();
}
#Override
public int getItemCount() {
if (orderLineList != null) {
return orderLineList.size();
} else {
return 0;
}
}
public class OrderLineViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView productCodeTextView, orderedQuantityTextView;
public CheckBox okCheckBox;
public OrderLineViewHolder(#NonNull View itemView) {
super(itemView);
productCodeTextView = itemView.findViewById(R.id.foam_in_product_code);
orderedQuantityTextView = itemView.findViewById(R.id.foam_in_quantity);
okCheckBox = itemView.findViewById(R.id.foam_in_checkbox);
okCheckBox.setOnClickListener(this);
productCodeTextView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
int position = getAdapterPosition();
OrderLine line = orderLineList.get(position);
switch (view.getId()) {
case R.id.foam_in_checkbox:
if (okCheckBox.isChecked()) {
line.setIsArrived(1);
orderLineViewModel.update(line);
orderLineList.remove(position);
notifyItemRemoved(position);
} else {
line.setIsArrived(0);
orderLineViewModel.update(line);
}
break;
case R.id.foam_in_product_code:
Toast.makeText(context, "Status: " + line.getIsArrived(), Toast.LENGTH_SHORT).show();
break;
}
}
}
#Override
public Filter getFilter() {
return orderFilter;
}
private Filter orderFilter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
List<OrderLine> filteredList = new ArrayList<>();
if (charSequence == null || charSequence.length() == 0){
filteredList.addAll(orderLineListFull);
}else {
String filterPattern = charSequence.toString().toLowerCase().trim();
for (OrderLine orderLine: orderLineListFull){
if (orderLine.getProductCode().toLowerCase().contains(filterPattern)){
filteredList.add(orderLine);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
orderLineList.clear();
orderLineList.addAll((List)filterResults.values);
notifyDataSetChanged();
}
};
Whole RecyclerViewAdapter:
public class OrderLineListAdapter extends RecyclerView.Adapter<OrderLineListAdapter.OrderLineViewHolder> implements Filterable {
private Context context;
private final LayoutInflater orderLineInflater;
private List<OrderLine> orderLineList;
private List<OrderLine> orderLineListFull;
private OrderLineViewModel orderLineViewModel;
public OrderLineListAdapter(Context context) {
this.context = context;
orderLineInflater = LayoutInflater.from(context);
orderLineViewModel = ViewModelProviders.of((FoamInActivity) context).get(OrderLineViewModel.class);
}
#NonNull
#Override
public OrderLineViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = orderLineInflater.inflate(R.layout.foam_in_single_line, parent, false);
return new OrderLineViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull OrderLineViewHolder orderLineViewHolder, int position) {
if (orderLineList != null) {
OrderLine current = orderLineList.get(position);
orderLineViewHolder.productCodeTextView.setText(current.getProductCode());
orderLineViewHolder.orderedQuantityTextView.setText(String.valueOf(current.getOrderedQuantity()));
orderLineViewHolder.okCheckBox.setOnCheckedChangeListener(null);
orderLineViewHolder.okCheckBox.setChecked(false);
} else {
orderLineViewHolder.productCodeTextView.setText(R.string.no_open_positions);
}
}
public void setOrderLines(List<OrderLine> orderLines) {
orderLineList = orderLines;
orderLineListFull = new ArrayList<>(orderLines);
notifyDataSetChanged();
}
#Override
public int getItemCount() {
if (orderLineList != null) {
return orderLineList.size();
} else {
return 0;
}
}
public class OrderLineViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView productCodeTextView, orderedQuantityTextView;
public CheckBox okCheckBox;
public OrderLineViewHolder(#NonNull View itemView) {
super(itemView);
productCodeTextView = itemView.findViewById(R.id.foam_in_product_code);
orderedQuantityTextView = itemView.findViewById(R.id.foam_in_quantity);
okCheckBox = itemView.findViewById(R.id.foam_in_checkbox);
okCheckBox.setOnClickListener(this);
productCodeTextView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
int position = getAdapterPosition();
OrderLine line = orderLineList.get(position);
switch (view.getId()) {
case R.id.foam_in_checkbox:
if (okCheckBox.isChecked()) {
line.setIsArrived(1);
orderLineViewModel.update(line);
orderLineList.remove(position);
notifyItemRemoved(position);
} else {
line.setIsArrived(0);
orderLineViewModel.update(line);
}
break;
case R.id.foam_in_product_code:
Toast.makeText(context, "Status: " + line.getIsArrived(), Toast.LENGTH_SHORT).show();
break;
}
}
}
#Override
public Filter getFilter() {
return orderFilter;
}
private Filter orderFilter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
List<OrderLine> filteredList = new ArrayList<>();
if (charSequence == null || charSequence.length() == 0){
filteredList.addAll(orderLineListFull);
}else {
String filterPattern = charSequence.toString().toLowerCase().trim();
for (OrderLine orderLine: orderLineListFull){
if (orderLine.getProductCode().toLowerCase().contains(filterPattern)){
filteredList.add(orderLine);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
orderLineList.clear();
orderLineList.addAll((List)filterResults.values);
notifyDataSetChanged();
}
};
}
Attaching a Sample : Please update your Adapter as
public class ListAdapter extends RecyclerView.Adapter<ListViewHolder> implements
Filterable {
private List<Status> statusList;
private List<Status> statusListFiltered;
private OnClickActionListener listener;
public ListAdapter(List<Status> statusList,
OnClickActionListener listener) {
this.statusList = statusList;
this.statusListFiltered = statusList;
this.listener = listener;
}
#Override
public void onBindViewHolder(#NonNull ListViewHolder holder, int position) {
Status status = statusListFiltered.get(position);
holder.cellListBinding.setStatus(status);
}
#Override
public int getItemCount() {
if (statusListFiltered != null) {
return statusListFiltered.size();
} else {
return 0;
}
}
#Override
public int getItemViewType(int position) {
return position;
}
#NonNull
#Override
public ListViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
CellListBinding binding = DataBindingUtil
.inflate(LayoutInflater.from(parent.getContext()), R.layout.cell_list,
parent, false);
return new ListViewHolder(binding);
}
/**
* Reloads list of rooms.
*/
public void loadRooms(List<Status> roomsList) {
this.statusList = roomsList;
this.statusListFiltered = roomsList;
notifyDataSetChanged();
}
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
if (charString.isEmpty()) {
statusListFiltered = statusList;
} else {
List<Status> filteredList = new ArrayList<>();
for (Status row : statusList) {
if (row.getStatusName().toLowerCase().contains(charString.toLowerCase()) {
filteredList.add(row);
}
}
statusListFiltered = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = statusListFiltered;
return filterResults;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
if (filterResults.values instanceof RealmList) {
statusListFiltered = (RealmList<Status>) filterResults.values;
} else {
statusListFiltered = (ArrayList<Status>) filterResults.values;
}
notifyDataSetChanged();
}
};
}
class ListViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
// Your Code
}
}
Related
Basically I am trying trying to implement checkboxes in recyclerview, but when I try to filter it, it unchecks the boxes. This is my adapter. I tried different adapters, but nothing seems to work.
IngAdapter.java
public class IngAdapter extends RecyclerView.Adapter<IngAdapter.ViewHolder> implements Filterable {
View view;
Context context;
ArrayList<String> getArrayList;
ArrayList<String> ingList;
IngListener ingListener;
ArrayList<String> arrayList_0 = new ArrayList<>();
public IngAdapter(Context context, ArrayList<String> arrayList, IngListener ingListener) {
this.context = context;
this.getArrayList = arrayList;
this.ingListener = ingListener;
this.ingList = new ArrayList<>(arrayList);
}
public View getView() {
return view;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
view = LayoutInflater.from(context).inflate(R.layout.rv_layout,parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, #SuppressLint("RecyclerView") int position) {
if (getArrayList != null && getArrayList.size() > 0) {
holder.check_box.setText((CharSequence) getArrayList.get(position));
holder.check_box.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (holder.check_box.isChecked()) {
arrayList_0.add(getArrayList.get(position));
} else {
arrayList_0.remove(getArrayList.get(position));
}
ingListener.onIngChange(arrayList_0);
}
});
}
}
#Override
public int getItemCount() {
return getArrayList.size();
}
Here is my filter function.
#Override
public Filter getFilter() {
return filter;
}
final Filter filter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
FilterResults filterResults = new FilterResults();
if (charSequence.toString().isEmpty()) {
filterResults.values = ingList;
filterResults.count = ingList.size();
} else {
String searchIng = charSequence.toString().toLowerCase();
List<String> filtered = new ArrayList<>();
for (String ingredient : ingList) {
if (ingredient.toLowerCase().contains(charSequence.toString().toLowerCase())) {
filtered.add(ingredient);
}
}
filterResults.values = filtered;
filterResults.count = filtered.size();
}
return filterResults;
}
#SuppressLint("NotifyDataSetChanged")
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
getArrayList.clear();
getArrayList.addAll((Collection<? extends String>) filterResults.values);
ingListener.onIngChange(arrayList_0);
notifyDataSetChanged();
}
};
[]
[]
I cannot find a solution to the same problem. Goal: Keep checkboxes selected after search
My mainAcivity2 code :
//for searchView
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
if(clientList.contains(query)){
adapter.getFilter().filter(query);
}else{
Toast.makeText(MainActivity2.this,"No Match Found",Toast.LENGTH_SHORT).show();
}
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
}
its my mainActiviy2 code where I want to implement the search View. I have 2 recycler views here. One is horizontal recycler View and the other is vertical recycler View. I want to use search View in vertical recycler View.
My adapter code:
public class ClientAdapter extends RecyclerView.Adapter<ClientAdapter.ClientViewHolder> implements Filterable {
private Context context;
private List<Clientt> clienttList;
List<Clientt> clienttListAll;
public ClientAdapter(Context context, List<Clientt> clienttList) {
this.context = context;
this.clienttList = clienttList;
}
#NonNull
#Override
public ClientViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.view_item_client, parent, false);
return new ClientAdapter.ClientViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ClientViewHolder holder, int position) {
holder.textViewClientName.setText(clienttList.get(position).getClientName());
holder.textViewClientNumber.setText(clienttList.get(position).getPhoneNumber());
String s = clienttList.get(position).getClientName();
}
#Override
public int getItemCount() {
return clienttList.size();
}
#Override
public Filter getFilter() {
return filter;
}
Filter filter=new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
if (charString.isEmpty()) {
clienttListAll = clienttList;
} else {
List<Clientt> filteredList = new ArrayList<>();
for (Clientt row : clienttList) {
// name match condition. this might differ depending on your requirement
// here we are looking for name or phone number match
if (row.getClientName().toLowerCase().contains(charString.toLowerCase()) || row.getPhoneNumber().contains(charSequence)) {
filteredList.add(row);
}
}
clienttListAll = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = clienttListAll;
return filterResults;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
clienttListAll = (ArrayList<Clientt>) filterResults.values;
// refresh the list with filtered data
notifyDataSetChanged();
}
};
public class ClientViewHolder extends RecyclerView.ViewHolder {
private TextView textViewClientName;
private TextView textViewClientNumber;
LinearLayout ly;
public ClientViewHolder(#NonNull View itemView) {
super(itemView);
textViewClientName = itemView.findViewById(R.id.text_view_client_name);
textViewClientNumber = itemView.findViewById(R.id.text_view_client_number);
ly = itemView.findViewById(R.id.listtt_Client);
}
}
}
When I run my application , it always a toast is shown whenever I search anything "No Match Found".
its the else part in my code...seems like "if" condition is not working.
Thankyou for your help in advance.
return true in your OnQueryTextListener
#Override
public boolean onQueryTextSubmit(String query)
{
adapter.filter(query);
return true;
}
#Override
public boolean onQueryTextChange(String newText)
{
adapter.filter(query);
return true;
}
adapter
public class ClientAdapter extends RecyclerView.Adapter<ClientAdapter.ClientViewHolder>
{
private Context context;
private List<Clientt> clienttList;
List<Clientt> clienttListAll;
public ClientAdapter(Context context, List<Clientt> clienttList)
{
this.context = context;
this.clienttList = clienttList;
clienttListAll.addAll(clienttList);
}
#NonNull
#Override
public ClientViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(context).inflate(R.layout.view_item_client, parent, false);
return new ClientAdapter.ClientViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ClientViewHolder holder, int position)
{
holder.textViewClientName.setText(clienttList.get(position).getClientName());
holder.textViewClientNumber.setText(clienttList.get(position).getPhoneNumber());
String s = clienttList.get(position).getClientName();
}
#Override
public int getItemCount()
{
return clienttList.size();
}
public void filter(String charText)
{
clienttList.clear();
if (charText.length() == 0)
{
clienttList.addAll(clienttListAll);
}
else
{
for (Clientt row : clienttListAll)
{
// name match condition. this might differ depending on your requirement
// here we are looking for name or phone number match
if (row.getClientName().toLowerCase().contains(charString.toLowerCase()) || row.getPhoneNumber().contains(charSequence))
{
clienttList.add(row);
}
}
}
notifyDataSetChanged();
}
public class ClientViewHolder extends RecyclerView.ViewHolder
{
private TextView textViewClientName;
private TextView textViewClientNumber;
LinearLayout ly;
public ClientViewHolder(#NonNull View itemView)
{
super(itemView);
textViewClientName = itemView.findViewById(R.id.text_view_client_name);
textViewClientNumber = itemView.findViewById(R.id.text_view_client_number);
ly = itemView.findViewById(R.id.listtt_Client);
}
}
}
Try this in your ClientAdapter:
public ClientAdapter(Context context, List<Clientt> clienttList)
{
this.context = context;
this.clienttList = clienttList;
clienttListAll=new Arraylist<>(clienttList);
}
Add this also:
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
clientList.clear();
clienttListAll.addAll((List) filterResults.values);
// refresh the list with filtered data
notifyDataSetChanged();
}
I will suggest you to try this full code IF nothing works:
My adapter code:
public class ClientAdapter extends RecyclerView.Adapter<ClientAdapter.ClientViewHolder> implements Filterable {
private Context context;
private List<Clientt> clienttList;
List<Clientt> clienttListAll;
public ClientAdapter(Context context, List<Clientt> clienttList) {
this.context = context;
this.clienttList = clienttList;
clientListAll=new Arraylist<>(clientList);
}
#NonNull
#Override
public ClientViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.view_item_client, parent, false);
return new ClientAdapter.ClientViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ClientViewHolder holder, int position) {
holder.textViewClientName.setText(clienttList.get(position).getClientName());
holder.textViewClientNumber.setText(clienttList.get(position).getPhoneNumber());
String s = clienttList.get(position).getClientName();
}
#Override
public int getItemCount() {
return clienttList.size();
}
#Override
public Filter getFilter() {
return filter;
}
Filter filter=new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
List<Clientt> filteredList= new Arraylist<>();
String charString = charSequence.toString();
if (charString.isEmpty()) {
filteredList.addAll(clienttListAll);
} else {
String filtered=charString.toLowerCase().trim();
for (Clientt row : clienttList) {
// name match condition. this might differ depending on your requirement
// here we are looking for name or phone number match
if (row.getClientName().toLowerCase().contains(filtered) || row.getPhoneNumber().contains(charSequence)) {
filteredList.add(row);
}
}
}
FilterResults filterResults = new FilterResults();
filterResults.values = filteredList;
return filterResults;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
clienList.clear();
clienttList.addAll((List)filterResults.values);
// refresh the list with filtered data
notifyDataSetChanged();
}
};
A search view is implemented in action bar, the search works fine, but for example,
If user search for two characters pa, my list contains 2 data related to the related to pa i.e., pack1,pack2 then data loads in the recycler view. now if user enter another character l, to the previous characters pa, now my search view has pal , but array list doesn't match with the search, the list doesn't contain any item with pal. i.e., now the recycler view is empty. now, if I clear the character l, the list gets reloaded with data pack1, pack2, but result loads 2 times i.e., instead of showing 2 items in recyclerview, it shows 4 items in total.
It is duplicating the items, when the search is cleared.
searchview
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_order, menu);
searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setMaxWidth(Integer.MAX_VALUE);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
mOrderAdapter.getFilter().filter(query);
searchView.clearFocus();
return true;
}
#Override
public boolean onQueryTextChange(String newText) {
if(newText.length()==0){
getData();
searchView.clearFocus();
}
mOrderAdapter.getFilter().filter(newText);
return true ;
}
});
return true;
}
Filter code
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
String charString = constraint.toString();
if (charString.isEmpty()||charString.length()==0) {
mListFilter = mOrderArrayList;
} else {
List<Order> filteredList = new ArrayList<>();
ArrayList<Order> templist=new ArrayList<Order>();
for (Order ord : mOrderArrayList) {
if (ord.getOs_OrderNo().toLowerCase().contains(charString.toLowerCase())
|| ord.getItemName().toLowerCase().contains(charString.toLowerCase())) {
filteredList.add(ord);
templist.addAll(mListFilter);
}
}
mOrderArrayList.removeAll(templist);
mOrderArrayList.addAll(filteredList);
mListFilter = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = mListFilter;
return filterResults;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
mListFilter = (ArrayList<Order>) results.values;
notifyDataSetChanged();
}
};
}
Any help is really appreciated.
Adapter code
public class OrderAdapter extends RecyclerView.Adapter<OrderAdapter.MyViewHolder> implements Filterable {
private Context mContext;
private List<Order> mListFilter,mOrderArrayList;
private SharedPreferences sharedPreferences;
private Resources r;
public OrderAdapter(Context context, ArrayList<Order> orderList) {
mContext = context;
mListFilter = orderList;
mOrderArrayList = orderList;
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
r = context.getResources();
}
class MyViewHolder extends RecyclerView.ViewHolder {
private TextView orderNoView, itemNameView, qtyView, statusView, companyNameView;
private Order currentItem;
MyViewHolder(View view) {
super(view);
orderNoView = view.findViewById(R.id.orderNo);
itemNameView = view.findViewById(R.id.item);
qtyView = view.findViewById(R.id.qty);
statusView = view.findViewById(R.id.status);
companyNameView = view.findViewById(R.id.company);
}
void bind (Order om) { //<--bind method allows the ViewHolder to bind to the data it is displaying
orderNoView.setText(om.getOs_OrderNo());
itemNameView.setText(String.valueOf(om.getItemName()));
qtyView.setText("Qty - " + String.valueOf(om.getOs_Qty()));
statusView.setText(om.getStatusName());
if (sharedPreferences.getString(r.getString(R.string.key_CompanyInUser), "").equals("0")){
companyNameView.setVisibility(View.GONE);
} else {
companyNameView.setText(om.getCustomerName());
}
currentItem = om; //<-- keep a reference to the current item
}
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.adapter_order, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
Order item = mListFilter.get(position);
holder.bind(item);
}
#Override
public int getItemCount() {
return mListFilter.size();
}
#Override
public int getItemViewType(int position){
return position;
}
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
String charString = constraint.toString();
List<Order> filteredList = new ArrayList<>();
if (charString.isEmpty()||charString.length()==0) {
filteredList.addAll(mOrderArrayList);
} else {
for (Order ord : mOrderArrayList) {
if (ord.getOs_OrderNo().toLowerCase().contains(charString.toLowerCase())
|| ord.getItemName().toLowerCase().contains(charString.toLowerCase())) {
filteredList.add(ord);
}
}
}
FilterResults filterResults = new FilterResults();
filterResults.values = filteredList;
return filterResults;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
mListFilter = (ArrayList<Order>) results.values;
notifyDataSetChanged();
}
};
}
}
Clicklistener code
brandView.addOnItemTouchListener(new RecyclerTouchListener(getApplicationContext(), brandView,
new RecyclerTouchListener.ClickListener() {
#Override
public void onClick(View view, int position) {
isRefreshData = true;
startActivity(new Intent(mContext, ViewOrderDetails.class).putExtra("Key-Intent-OrderNo",mOrderArrayList.get(position).getOs_OrderNo()).putExtra("Key-Intent-BrandName",mOrderArrayList.get(position).getos_BrandName()));
}
#Override
public void onLongClick(View view, int position) {
}
}));
Its because you are using addAll inside a loop in #performFiltering . Also why you have two local list for filtering? Check the method below it should work . i have removed the extra code and code which is causing the issue .
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
String charString = constraint.toString();
List<Order> filteredList = new ArrayList<>();
if (charString.isEmpty()||charString.length()==0) {
filteredList.addAll(mOrderArrayList);
} else {
for (Order ord : mOrderArrayList) {
if (ord.getOs_OrderNo().toLowerCase().contains(charString.toLowerCase())
|| ord.getItemName().toLowerCase().contains(charString.toLowerCase())) {
filteredList.add(ord);
}
}
}
FilterResults filterResults = new FilterResults();
filterResults.values = filteredList;
return filterResults;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
mListFilter = (ArrayList<Order>) results.values;
notifyDataSetChanged();
}
};
}
So I have a little problem where I have a giant recycler view (7000 items) and I have it filled up with generated cards that have college information on them and a button on the right hand side. I included a picture for you to see exactly what I mean. So here is the question: I want to fetch the name and ID when I click on the "details" button so that I can query the rest of college information from an SQLite database later but when I scroll down enough and click the button it sometimes returns information of other college instead of the one I want. The first one always works as intended though. Here is the adapter code:
public class CustomRecyclerAdapter extends RecyclerView.Adapter<CustomRecyclerAdapter.CustomViewHolder> implements Filterable {
private List<CollegeItem> collegeList;
private List<CollegeItem> collegeListFull;
private ItemClickListener itemClickListener;
private Context context;
private Button details;
private DatabaseCollege collegeDB;
public CustomRecyclerAdapter(List<CollegeItem> collegeList, Context context) {
this.collegeList = collegeList;
this.context = context;
collegeListFull = new ArrayList<>(collegeList);
}
#NonNull
#Override
public CustomRecyclerAdapter.CustomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(context).inflate(R.layout.college_item, parent, false);
return new CustomRecyclerAdapter.CustomViewHolder(itemView);
}
#Override
public void onBindViewHolder(CustomRecyclerAdapter.CustomViewHolder holder, int position) {
final String id = collegeList.get(position).getId();
final String name = collegeList.get(position).getName();
holder.name.setText(collegeList.get(position).getName());
holder.id.setText(collegeList.get(position).getId());
details.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.println(id + " - " + name); //This sometimes gives information of incorrect college when clicked
}
});
}
#Override
public int getItemCount() {
return collegeList.size();
}
public void setItemClickListener(ItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
#Override
public Filter getFilter() {
return collegeFilter;
}
public Filter getFilterName() {
return collegeFilterName;
}
private Filter collegeFilter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
List<CollegeItem> filteredList = new ArrayList<>();
if(constraint == null || constraint.length() == 0) {
filteredList.addAll(collegeListFull);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for(CollegeItem college : collegeListFull) {
if(college.getName().toLowerCase().contains(filterPattern)) {
filteredList.add(college);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
collegeList.clear();
collegeList.addAll((List) results.values);
notifyDataSetChanged();
}
};
private Filter collegeFilterName = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
List<CollegeItem> filteredList = new ArrayList<>();
if(constraint == null || constraint.length() == 0) {
filteredList.addAll(collegeListFull);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for(CollegeItem college : collegeListFull) {
if(college.getId().toLowerCase().contains(filterPattern)) {
filteredList.add(college);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
collegeList.clear();
collegeList.addAll((List) results.values);
notifyDataSetChanged();
}
};
public class CustomViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView name, id;
public CustomViewHolder(View v) {
super(v);
name = v.findViewById(R.id.college_name);
id = v.findViewById(R.id.college_id);
details = v.findViewById(R.id.btn_college_details);
}
#Override
public void onClick(View v) {
if(itemClickListener != null) {
itemClickListener.onClick(v, getAdapterPosition());
}
}
}
}
I am not sure exactly why but it seems to be a positioning issue maybe? Because when I scroll and click the information outputed seem to change. Whats the correct way to get the information from the cards the way I want?
and just in case here is the fragment java code where the recycler view sits:
public class CollegeFragment extends Fragment implements ItemClickListener{
private RecyclerView recyclerView;
private CustomRecyclerAdapter customRecyclerAdapter;
private List<CollegeItem> collegeItemList = new ArrayList<>();
private DatabaseCollege dbCollege;
private EditText cName, cId;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View myFragmentView = inflater.inflate(R.layout.fragment_college, container, false);
dbCollege = new DatabaseCollege(getActivity());
recyclerView = myFragmentView.findViewById(R.id.recycler);
customRecyclerAdapter = new CustomRecyclerAdapter(dbCollege.getCollegeData(), getActivity());
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(customRecyclerAdapter);
customRecyclerAdapter.setItemClickListener(this);
cId = myFragmentView.findViewById(R.id.et_ipeds);
cId.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) {
cName.getText().clear();
CollegeFragment.this.customRecyclerAdapter.getFilter().filter(s);
}
#Override
public void afterTextChanged(Editable s) {
}
});
cName = myFragmentView.findViewById(R.id.et_name);
cName.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) {
cId.getText().clear();
CollegeFragment.this.customRecyclerAdapter.getFilterName().filter(s);
}
#Override
public void afterTextChanged(Editable s) {
}
});
return myFragmentView;
}
#Override
public void onClick(View v, int position) {
String name = collegeItemList.get(position).getName();
String id = collegeItemList.get(position).getId();
}
}
Adapter
public class CustomRecyclerAdapter extends RecyclerView.Adapter<CustomRecyclerAdapter.CustomViewHolder> implements Filterable {
private List<CollegeItem> collegeList;
private List<CollegeItem> collegeListFull;
private ItemClickListener itemClickListener;
private Context context;
private DatabaseCollege collegeDB;
public CustomRecyclerAdapter(List<CollegeItem> collegeList, Context context) {
this.collegeList = collegeList;
this.context = context;
collegeListFull = new ArrayList<>(collegeList);
}
#NonNull
#Override
public CustomRecyclerAdapter.CustomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(context).inflate(R.layout.college_item, parent, false);
return new CustomRecyclerAdapter.CustomViewHolder(itemView);
}
#Override
public void onBindViewHolder(CustomRecyclerAdapter.CustomViewHolder holder, int position) {
final String id = collegeList.get(position).getId();
final String name = collegeList.get(position).getName();
holder.name.setText(collegeList.get(position).getName());
holder.id.setText(collegeList.get(position).getId());
}
#Override
public int getItemCount() {
return collegeList.size();
}
public void setItemClickListener(ItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
#Override
public Filter getFilter() {
return collegeFilter;
}
public Filter getFilterName() {
return collegeFilterName;
}
private Filter collegeFilter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
List<CollegeItem> filteredList = new ArrayList<>();
if(constraint == null || constraint.length() == 0) {
filteredList.addAll(collegeListFull);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for(CollegeItem college : collegeListFull) {
if(college.getName().toLowerCase().contains(filterPattern)) {
filteredList.add(college);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
collegeList.clear();
collegeList.addAll((List) results.values);
notifyDataSetChanged();
}
};
private Filter collegeFilterName = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
List<CollegeItem> filteredList = new ArrayList<>();
if(constraint == null || constraint.length() == 0) {
filteredList.addAll(collegeListFull);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for(CollegeItem college : collegeListFull) {
if(college.getId().toLowerCase().contains(filterPattern)) {
filteredList.add(college);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
collegeList.clear();
collegeList.addAll((List) results.values);
notifyDataSetChanged();
}
};
public class CustomViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView name, id;
Button details; // Button should be here
public CustomViewHolder(View v) {
super(v);
name = v.findViewById(R.id.college_name);
id = v.findViewById(R.id.college_id);
details = v.findViewById(R.id.btn_college_details);
details.setOnClickListener(this); // set click listener here instead
}
#Override
public void onClick(View v) {
if(itemClickListener != null) {
itemClickListener.onClick(v, getAdapterPosition());
}
}
}
}
Here, you're utilizing the ItemClickListener callback that you implemented in your fragment instead of creating new instances of click listener for your details button. In this case, your listener for all items is your Fragment that implements ItemClickListener
I'm using well RealmRecyclerViewAdapter. My problem is to implement a Filterable that not works. This is the code:
private class AirportAdapter extends RealmRecyclerViewAdapter<AirportR,RecyclerView.ViewHolder> implements Filterable
{
Context context;
OrderedRealmCollection<AirportR>listAirports;
public AirportAdapter(Context activity, OrderedRealmCollection<AirportR>airports)
{
super(activity,airports, true);
this.context = activity;
this.listAirports = airports;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.airport_show, parent,false);
AirportClass holder = new AirportClass(view);
return holder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
AirportR airportR = listAirports.get(position);
AirportClass mHolder = (AirportClass)holder;
mHolder.country.setText(airportR.getIsoCountry());
mHolder.name.setText(airportR.getName());
}
public Filter getFilter()
{
AirportFilter filter = new AirportFilter(this, listAirports);
return filter;
}
private class AirportFilter extends Filter
{
private final AirportAdapter adapter;
OrderedRealmCollection<AirportR>originalList;
OrderedRealmCollection<AirportR>filteredList;
private AirportFilter(AirportAdapter adapter, OrderedRealmCollection<AirportR> originalList)
{
super();
this.adapter = adapter;
this.originalList = originalList;
}
#Override
protected FilterResults performFiltering(CharSequence constraint)
{
filteredList.clear();
final FilterResults results = new FilterResults();
if (constraint.length() == 0)
{
filteredList.addAll(originalList);
}
else
{
final String filterPattern = constraint.toString().toLowerCase().trim();
for (final AirportR airportR : originalList)
{
if (airportR.getName().toLowerCase().contains(filterPattern))
{
filteredList.add(airportR);
}
}
}
results.values = filteredList;
results.count = filteredList.size();
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results)
{
adapter.listAirports.addAll((OrderedRealmCollection<AirportR>) results.values);
adapter.notifyDataSetChanged();
}
}
private class AirportClass extends RecyclerView.ViewHolder
{
TextView name, country;
ImageView image;
public AirportClass(View itemView)
{
super(itemView);
name = (TextView)itemView.findViewById(R.id.name);
country = (TextView)itemView.findViewById(R.id.country);
image = (ImageView)itemView.findViewById(R.id.imageView);
}
}
}
and I give back the error:
java.lang.UnsupportedOperationException: This method is not supported by RealmResults.
at io.realm.RealmResults.addAll(RealmResults.java:710)
at com.example.matteo.downloadairports.fragment.ListAirportFragment$AirportAdapter$AirportFilter.publishResults
how could I save the result after I filter it and update the adapter?
Thanks
Move the filtering to publishResults and use the UI thread Realm's queries to evaluate the new results.
private class AirportAdapter
extends RealmRecyclerViewAdapter<AirportR, RecyclerView.ViewHolder>
implements Filterable {
Realm realm;
public AirportAdapter(Context context, Realm realm, OrderedRealmCollection<AirportR> airports) {
super(context, airports, true);
this.realm = realm;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.airport_show, parent, false);
AirportClass holder = new AirportClass(view);
return holder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
AirportR airportR = getData().get(position);
AirportClass mHolder = (AirportClass) holder;
mHolder.bind(airportR);
}
public void filterResults(String text) {
text = text == null ? null : text.toLowerCase().trim();
RealmQuery<AirportR> query = realm.where(AirportR.class);
if(!(text == null || "".equals(text))) {
query.contains("fieldToQueryBy", text, Case.INSENSITIVE) // TODO: change field
}
updateData(query.findAllAsync());
}
public Filter getFilter() {
AirportFilter filter = new AirportFilter(this);
return filter;
}
private class AirportFilter
extends Filter {
private final AirportAdapter adapter;
private AirportFilter(AirportAdapter adapter) {
super();
this.adapter = adapter;
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
return new FilterResults();
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
adapter.filterResults(constraint.toString());
}
}
private class AirportClass
extends RecyclerView.ViewHolder {
TextView name, country;
ImageView image;
public AirportClass(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.name);
country = (TextView) itemView.findViewById(R.id.country);
image = (ImageView) itemView.findViewById(R.id.imageView);
}
public void bind(AirportR airportR) {
country.setText(airportR.getIsoCountry());
name.setText(airportR.getName());
}
}
}
in your adapter add this it may help you
fun filterResults(text: String?, realm: Realm) {
var text = text
text = text?.toLowerCase()?.trim { it <= ' ' }
val query = realm.where(YourObject::class.java)
if (!(text == null || "" == text)) {
query.contains("username", text, Case.INSENSITIVE).or().contains("username2", text, Case.INSENSITIVE)
}
updateData(query.findAllAsync()) // or findAll()
}