I have a Listview with a Custom BaseAdapter. I have already done the code for my MainActivity.java to apply SearchView. However, I have problem with the performFiltering method in my Adapter class due to the reason that I have a ImageView that would be shown on my ListView. The ImageView is originally in the form of String because I would like to get the image from an url in my Firebase Storage and then convert it to Image by using the Picasso library.
TL:DR. My problem is that everytime I perform a search, the url of the image stored in Firebase is showing up instead of the actual Image. Help is appreciated thanks.
Below is my Adapter Class:
public class GridAdapter extends BaseAdapter implements Filterable {
CustomFilter mCustomFilter;
ArrayList<GridItem> filterList;
private Context mContext;
private ArrayList<GridItem> gtem;
//Constructor
public GridAdapter(Context mContext, ArrayList<GridItem> gtem) {
this.filterList = gtem;
this.mContext = mContext;
this.gtem = gtem;
}
#Override
public int getCount() {
return gtem.size();
}
#Override
public Object getItem(int position) {
return gtem.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = View.inflate(mContext,R.layout.grid_item, null);
ImageView putPic = (ImageView)v.findViewById(R.id.imageHere);
TextView putTitle = (TextView)v.findViewById(R.id.titleHere);
TextView putPrice = (TextView)v.findViewById(R.id.per_price);
TextView putCountry = (TextView)v.findViewById(R.id.countryHere);
//
putCountry.setText("Country: " + gtem.get(position).getCountry());
putTitle.setText(gtem.get(position).getmTitleHere());
putCountry.setText(gtem.get(position).getCountry());
putPrice.setText("Price: " + "$" + gtem.get(position).getmPriceHere());
Picasso.with(mContext).load(gtem.get(position).getmImageView()).resize(450 , 500).into(putPic);
return v;
}
#Override
public Filter getFilter() {
//To-do Auto-generated method stub
if (mCustomFilter == null )
{
mCustomFilter = new CustomFilter();
}
return mCustomFilter;
}
//Inner Class
class CustomFilter extends Filter
{
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length()>0)
{
//Constraint to Upper
constraint = constraint.toString().toUpperCase();
ArrayList<GridItem> filters = new ArrayList<GridItem>();
//to get specific items
for (int i = 0; i<filterList.size(); i++)
{
if (filterList.get(i).getmTitleHere().toUpperCase().contains(constraint))
{
GridItem g = new GridItem(filterList.get(i).getmTitleHere() , filterList.get(i).getmPriceHere(), filterList.get(i).getmImageView()
, filterList.get(i).getCountry());
filters.add(g);
}
}
results.count = filters.size();
results.values = filters;
}else {
results.count = filterList.size();
results.values = filterList;
}
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
gtem = (ArrayList<GridItem>) results.values;
notifyDataSetChanged();
}
}
}
Related
I have a Search filter which has to filter the items based on the text input. Each list item consists of two TextViews and one ImageView. I have attached adapters and the filter is working fine with the two textviews but the corresponding ImageViews are not getting filtered (the order of images is not changing).
I tried to change the code in several ways but its not working. In here, my Adapter extends ArrayAdapter. I tried using the BaseAdapter too, but still doesn't work
My Adapter class:
import de.hdodenhof.circleimageview.CircleImageView;
public class ChefSearchResultAdapter extends ArrayAdapter<ChefSearchItem> implements Filterable {
private ArrayList<ChefSearchItem> modelValues;
private List<ChefSearchItem> mOriginalValues;
private Context context;
private static class ViewHolder {
TextView userName;
TextView userAdmirers;
CircleImageView userProfileImage;
}
public ChefSearchResultAdapter(Context context, ArrayList<ChefSearchItem> chefs) {
super(context, 0, chefs);
modelValues = chefs;
this.context=context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
ChefSearchItem chef = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
final ViewHolder viewHolder; // view lookup cache stored in tag
if (convertView == null) {
// If there's no view to re-use, inflate a brand new view for row
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.chef_search_listitem, parent, false);
viewHolder.userName = convertView.findViewById(R.id.user_name);
viewHolder.userAdmirers = convertView.findViewById(R.id.user_admirers);
viewHolder.userProfileImage = convertView.findViewById(R.id.profile_image);
// Cache the viewHolder object inside the fresh view
convertView.setTag(viewHolder);
} else {
// View is being recycled, retrieve the viewHolder object from tag
viewHolder = (ViewHolder) convertView.getTag();
}
final StorageReference storageReference = FirebaseStorage.getInstance().getReference("Users").child(chef.userUID);
storageReference.child("Profile Pic").getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
//Picasso.get().load(uri).into(viewHolder.userProfileImage);
Picasso.get()
.load(uri)
.networkPolicy(NetworkPolicy.OFFLINE)
.into(viewHolder.userProfileImage, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError(Exception e) {
Picasso.get()
.load(uri)
.into(viewHolder.userProfileImage, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError(Exception e) {
Log.v("Picasso","Could not fetch image");
}
});
}
});
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Handle any errors
}
});
// Populate the data from the data object via the viewHolder object
// into the template view.
viewHolder.userName.setText(chef.userName);
viewHolder.userAdmirers.setText(chef.userAdmirers);
//Set on click to listitem
LinearLayout listItem = convertView.findViewById(R.id.chef_listitem);
listItem.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Navigate user to selected chef profile
Intent i=new Intent(context,ChefsViewActivity.class);
i.putExtra("UID",chef.userUID);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
});
// Return the completed view to render on screen
return convertView;
}
#Override
public Filter getFilter() {
Filter filter = new Filter() {
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
modelValues.clear();
modelValues.addAll((ArrayList<ChefSearchItem>) results.values);
notifyDataSetChanged();
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
// Holds the results of a filtering values
List<ChefSearchItem> FilteredArrList = new ArrayList<>();
if (mOriginalValues == null) {
mOriginalValues = new ArrayList<>(modelValues); // saves
}
/********
*
* If constraint(CharSequence that is received) is null returns
* the mOriginalValues(Original) values else does the Filtering
* and returns FilteredArrList(Filtered)
*
********/
if (constraint == null || constraint.length() == 0) {
// set the Original result to return
results.count = mOriginalValues.size();
results.values = mOriginalValues;
} else {
Locale locale = Locale.getDefault();
constraint = constraint.toString().toLowerCase(locale);
for (int i = 0; i < mOriginalValues.size(); i++) {
ChefSearchItem model = mOriginalValues.get(i);
String data = model.userName;
if (data.toLowerCase(locale).contains(constraint.toString())) {
FilteredArrList.add(model);
}
}
// set the Filtered result to return
results.count = FilteredArrList.size();
results.values = FilteredArrList;
}
return results;
}
};
return filter;
}
}
My ViewHolder:
public class ChefSearchItem {
public String userName;
public String userAdmirers;
public String userUID;
public ChefSearchItem(String userName, String userAdmirers, String userUID) {
this.userName = userName;
this.userAdmirers = userAdmirers;
this.userUID = userUID;
}
}
More simpler way to filter out data is filter them locally
In your activity where your searchview is on submit call this method and pass the search string as parameter.
Make a temporary list which will consist of filterdata.
filter(String filter){
ArrayList<ChefSearchItem> filtereModelValues = new ArrayList<ChefSearchItem>();
for (ChefSearchItem chefSearchItem : <LIST YOU ARE SENDING TO ADAPTER>){
if(filter.toLowerCase().equals(chechefSearchItem.userUID.toLowerCase())
filtereModelValues.add(chefSearchItem );
}
//outside the for loop send the filtered list to adapter by creating method inside adapter name "filter" and pass filterList as parameter.
YOUR_ADAPTER.filter(filtereModelValues);
}
And in your adapter
public void filter(ArrayList<ChefSearchItem> filterModelValues){
modelValues = filterModelValues;
notifyDataChanged();
}
I have 90 images that I want to display on a scrolling activity , the first 20 images appear with no problem , but when I scroll donw the app shuts down immediatly
so I want to display only the first 20 Objects , then when the user scrolls down I destroy the first row and create a new row and so on , so the machine won't have to load all the 90 Objects at once
here's my code :
ArrayList<Hero> heroes;
SearchView searchView;
GridAdapter gridAdapter;
String[] names = {"Akai","(and 90 more Strings)" };
Integer[] images = {R.drawable.akai , (and 90 more Images) };
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_heroes);
CreateList();
GridView gridView = findViewById(R.id.gridView);
gridAdapter = new GridAdapter(this, heroes);
gridView.setAdapter(gridAdapter);
gridView.setNumColumns(4);
searchView = (SearchView) findViewById(R.id.search_view);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
gridAdapter.getFilter().filter(newText);
return false;
}
});
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent toAtt = new Intent(getApplication(),HeroAttributes.class);
toAtt.putExtra("item",heroes.get(position).getButton());
startActivity(toAtt);
}
});
}
public void CreateList() {
heroes = new ArrayList<>();
for (int i=0 ; i<names.length ; i++) {
Hero hero = new Hero(images[i] , names[i]);
heroes.add(hero);
}
}
My GridAdapter code :
public class GridAdapter extends BaseAdapter implements Filterable {
private Context myLayout;
private ArrayList<Hero> heroes;
private ArrayList<Hero> filterHeroes;
MyFilter filter;
public GridAdapter(Context context , ArrayList<Hero> heroes ) {
this.myLayout = context;
this.heroes = heroes;
this.filterHeroes = heroes;
}
#Override
public Filter getFilter() {
if (filter == null) {
filter = new MyFilter();
}
return filter;
}
#Override
public int getCount() {
return heroes.size();
}
#Override
public Object getItem(int position) {
return heroes.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup
parent) {
LayoutInflater inflater = LayoutInflater.from(myLayout);
if (convertView == null) {
convertView = inflater.inflate(R.layout.grid_items , parent ,
false);
}
TextView textView = (TextView) convertView.findViewById(R.id.txt);
ImageView imageView = (ImageView) convertView.findViewById(R.id.btn);
textView.setText(heroes.get(position).getTextView());
imageView.setImageResource(heroes.get(position).getButton());
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent toAtt = new Intent(Heroes.this,HeroAttributes.class);
toAtt.putExtra("item",heroes.get(position));
startActivity(toAtt);
}
});
return convertView;
}
class MyFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
constraint = constraint.toString().toUpperCase();
ArrayList<Hero> heroes2 = new ArrayList<>();
for (int i=0 ; i<filterHeroes.size() ; i++){
if(filterHeroes.get(i).getTextView().toUpperCase().contains(constraint)){
heroes2.add(filterHeroes.get(i));
}
}
results.count = heroes2.size();
results.values = heroes2;
}
else {
results.count = filterHeroes.size();
results.values = filterHeroes;
}
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults
results) {
heroes = (ArrayList<Hero>) results.values;
notifyDataSetChanged();
}
}
}
Probably one of your images has large resolution. Use Picasso or Glide to help this problem instead using the image directly, they are great at scaling image and resizing image.
Picasso : https://square.github.io/picasso/
Glide : https://github.com/bumptech/glide
the example of Picasso is
Picasso.get().load(heroes.get(position).getButton()).into(imageView);
the example of Glide is
Glide.with(context).load(heroes.get(position).getButton()).into(imageView);
instead directly imageView.setImageResource(heroes.get(position).getButton());
Hope it helps!
I've got a list view that I'm trying to filter depending on which button the user clicks.
The filter is working, I'm getting the results I expect inside the publishResults method but the list is then never updating. I've got notifyDataSetChanged() but this doesn't seem to do anything.
Min SDK level 21 and compiled 26.
mAdapter = new QuakeAdapter(this, new ArrayList<QuakeItem>());
ListView earthquakeListView = (ListView) findViewById(R.id.list);
earthquakeListView.setAdapter(mAdapter);
Setting the filter
public void filterList(View view){
mAdapter.resetData();
Log.d(LOG_TAG, "FILTER Tsunami" + mAdapter.quakeList);
mAdapter.getFilter().filter("tsunamiOnly");
}
public void filterListEarthquake(View view){
mAdapter.resetData();
Log.d(LOG_TAG, "FILTER earthquake" + mAdapter.quakeList);
mAdapter.getFilter().filter("earthquakeOnly");
}
Custom Adapter
public class QuakeAdapter extends ArrayAdapter<QuakeItem> implements Filterable {
public ArrayList<QuakeItem> origQuakeList;
public ArrayList<QuakeItem> quakeList;
private Filter quakeFilter;
private Context mContext;
public static final String LOG_TAG = QuakeAdapter.class.getName();
public QuakeAdapter(Activity context, ArrayList<QuakeItem> quakeItems){
super(context, 0, quakeItems);
origQuakeList = quakeItems;
quakeList = quakeItems;
mContext = context;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent){
View listItemView = convertView;
if(listItemView == null){
listItemView = LayoutInflater.from(getContext()).inflate(
R.layout.list_item, parent, false
);
}
QuakeItem currentItem = getItem(position);
double mag = currentItem.getMagnitude();
TextView magnitudeTextView = (TextView) listItemView.findViewById(R.id.magnitudeView);
magnitudeTextView.setText(formatMagnitude(mag));
GradientDrawable magnitudeCircle = (GradientDrawable) magnitudeTextView.getBackground();
int magnitudeColour = getMagnitudeColour(mag);
magnitudeCircle.setColor(magnitudeColour);
int isTsunami = currentItem.getTsunami();
int strokeColor = magnitudeColour;
if (isTsunami==1){
strokeColor = Color.BLACK;
}
magnitudeCircle.setStroke(6, strokeColor);
String[] formattedString = formatLocation(currentItem.getLocation());
TextView locationOffsetTextView = (TextView) listItemView.findViewById(R.id.locationOffsetView);
locationOffsetTextView.setText(formattedString[0]);
TextView locationTextView = (TextView) listItemView.findViewById(R.id.locationView);
locationTextView.setText(formattedString[1]);
Long timeInMilliseconds = currentItem.getTime();
TextView timeTextView = (TextView) listItemView.findViewById(R.id.timeView);
timeTextView.setText(formatTime(timeInMilliseconds));
TextView dateTextView = (TextView) listItemView.findViewById(R.id.dateView);
dateTextView.setText(formatDate(timeInMilliseconds));
return listItemView;
}
public void resetData() {
quakeList = origQuakeList;
}
#Override
public Filter getFilter() {
if (quakeFilter == null)
quakeFilter = new QuakeFilter();
return quakeFilter;
}
private class QuakeFilter extends Filter{
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint == null || constraint.length() == 0){
// No filter found, return original list
results.values = origQuakeList;
results.count = origQuakeList.size();
} else {
// Perform filter
ArrayList<QuakeItem> nQuakeList = new ArrayList<QuakeItem>();
switch (constraint.toString()){
case "tsunamiOnly":
for (QuakeItem q : quakeList){
if (q.getTsunami() == 1){
nQuakeList.add(q);
}
}
break;
case "earthquakeOnly":
for (QuakeItem q : quakeList){
if (q.getTsunami() == 0){
nQuakeList.add(q);
}
}
break;
}
results.values = nQuakeList;
results.count = nQuakeList.size();
}
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults filterResults) {
if (filterResults.count == 0){
notifyDataSetInvalidated();
} else {
quakeList = (ArrayList<QuakeItem>) filterResults.values;
Log.d(LOG_TAG, "FILTER " + quakeList);
notifyDataSetChanged();
}
}
}
}
Solved my own problem. As expected it was something stupid.
I was missing getCount, getItem and getItemId in my adapter.
public int getCount() {
return quakeList.size();
}
public QuakeItem getItem(int position) {
return quakeList.get(position);
}
public long getItemId(int position) {
return quakeList.get(position).hashCode();
}
I need help in implementing filterable interface for my list view items in a note app am currently working on. I have tried several ways but am not getting the expected result. For now it just does nothing after tying a search item.
I have implemented all the necessary methods in my adapter class and main activity.
I really need some help as i am quite new to this.Thanks in anticipation for positive replies.
// Note.java
public class Note implements Serializable {
private long mDateTime; //creation time of the note
private String mTitle; //title of the note
private String mContent; //content of the note
public Note(long dateInMillis, String title, String content) {
mDateTime = dateInMillis;
mTitle = title;
mContent = content;
}
public void setDateTime(long dateTime) {
mDateTime = dateTime;
}
public void setTitle(String title) {
mTitle = title;
}
public void setContent(String content) {
mContent = content;
}
public long getDateTime() {
return mDateTime;
}
}
public String getTitle() {
return mTitle;
}
public String getContent() {
return mContent;
}
}
// ArrayAdapter which implements Filterable
class NoteListAdapter extends ArrayAdapter<Note> implements Filterable{
List<Note> objects;
private List<Note> mStringFilterList;
Filter filter;
private static final int WRAP_CONTENT_LENGTH = 5;
public NoteListAdapter(Context context, int resource, List<Note> objects) {
super(context, resource, objects);
this.objects = objects;
this.mStringFilterList = objects;
}
#Override
public int getCount() {
return objects.size();
}
#Nullable
#Override
public Note getItem(int position) {
return objects.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public Filter getFilter() {
filter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
ArrayList<Note> tempList=new ArrayList<Note>();
FilterResults results = new FilterResults();
if (constraint != null && objects != null) {
for(Note singleNote : objects) {
if( singleNote.getTitle().contains(constraint))
tempList.add(singleNote);
}
results.values = tempList;
results.count = tempList.size();
}
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
objects = (ArrayList<Note>) results.values;
notifyDataSetChanged();
}
};
return filter;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = LayoutInflater.from(getContext())
.inflate(R.layout.list_component, parent, false);
}
return convertView;
}
}
// Main Activity
#Override
public boolean onQueryTextSubmit(String query) {
ArrayList<Note> notes = Utilities.getAllSavedNotes(getApplicationContext());
final NoteListAdapter na = new NoteListAdapter(this, R.layout.list_component, notes);
na.getFilter().filter(query);
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
return false;
}
}
You're returning super.getFilter() instead of your filter you just created. And also, you're not filtering anything in the Filter performFiltering() method as you're adding every item to the results if the CharSequence has something and the adapter has items.
I would suggest something like that:
protected FilterResults performFiltering(CharSequence constraint) {
ArrayList<Note> tempList=new ArrayList<Note>();
FilterResults results = new FilterResults();
if (constraint != null && objects != null) {
for(Note singleNote : objects) {
if( singleNote.getTitle().contains(constraint)
tempList.add(singleNote);
}
results.values = tempList;
results.count = tempList.size();
}
return results;
}
EDITS:
Also, in the activity, inside the
#Override
public boolean onQueryTextSubmit(String query) {
ArrayList<Note> notes = Utilities.getAllSavedNotes(getApplicationContext());
final NoteListAdapter na = new NoteListAdapter(this, R.layout.list_component, notes);
na.getFilter().filter(query);
return false;
}
You're using a new adapter without setting it to the recyclerView/listView.
Try using the adapter you create inside the onCreate() of the activity or try using recyclerView/listView.setAdapter(na) after you change the adapter using the na.getFilter().filter(query);
EDITS2:
So, if you want your filter to be performed whenever the user input something move the code from the onQueryTextSubmit() to the onQueryTextChanged().
For the improvement you asked for (when the string is empty reload the full list) you have 2 ways:
First way:
#Override
public boolean onQueryTextChanged(String query) {
if (!query.equals("")) {
ArrayList<Note> notes = Utilities.getAllSavedNotes(getApplicationContext());
final NoteListAdapter na = new NoteListAdapter(this, R.layout.list_component, notes);
na.getFilter().filter(query);
} else {
ArrayList<Note> notes = Utilities.getAllSavedNotes(getApplicationContext());
final NoteListAdapter na = new NoteListAdapter(this, R.layout.list_component, notes);
}
return false;
}
The other way could be inside the performFiltering() method of the Filter interface implementation. You could also check if the string is empty there, and if so you need to return the full list, without creating a new support one in which you add elements only if certain condition are match.
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()
}