How to filter the data in realm adapter?
public void setFilter( List<RealmPhoneCallLogs> filtedData) {
filter = new ArrayList<>(); // <-- WRONG
filter.addAll(filtedData); // <-- WRONG
private List<RealmPhoneCallLogs> filter(List<RealmPhoneCallLogs> models, String query) {
query = query.toLowerCase();
final List<RealmPhoneCallLogs> filteredModelList = new ArrayList<>(); // <-- WRONG
for (RealmPhoneCallLogs model : models) { // <-- WRONG
final String text = model.getNumber().toLowerCase();
if (text.contains(query)) { // <-- WRONG: should be Realm query
Instead, you need to do
// from https://stackoverflow.com/a/33818311/2413303
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
adapter.getFilter().filter(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
if (searchView.getQuery().length() == 0) {
adapter.getFilter().filter("");
}
return false;
}
});
Then just like in the linked answer
private class MyNamesAdapter
extends RealmBaseAdapter<RealmPhoneCallLogs>
implements Filterable {
public MyNamesAdapter(OrderedRealmCollection<RealmPhoneCallLogs> data) {
super(data);
}
public class ViewHolder {
TextView number;
TextView callType;
TextView startTime;
TextView contactName;
TextView callDuration;
TextView fileSize;
ImageView contactPhoto;
ImageView callSymbol;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final RealmPhoneCallLogs realmPhoneCallLogs = getItem(position);
ViewHolder viewHolder;
if(convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.calllog_layout, parent, false);
viewHolder.number = (TextView) convertView.findViewById(R.id.missedNumber);
viewHolder.startTime = (TextView) convertView.findViewById(R.id.missedStartTime);
viewHolder.contactName = (TextView) convertView.findViewById(R.id.missedContactName);
viewHolder.callDuration = (TextView) convertView.findViewById(R.id.missedCallDuration);
viewHolder.fileSize = (TextView) convertView.findViewById(R.id.missedFileSize);
viewHolder.contactPhoto = (ImageView) convertView.findViewById(R.id.missedImage);
viewHolder.callSymbol = (ImageView) convertView.findViewById(R.id.callSymbol);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
if(adapterData != null) {
viewHolder.number.setText(realmPhoneCallLogs.getNumber());
viewHolder.contactName.setText(getContactName(realmPhoneCallLogs.getNumber()));
viewHolder.callDuration.setText(getTime(realmPhoneCallLogs.getCallDuration()));
viewHolder.startTime.setText(realmPhoneCallLogs.getStartTime());
viewHolder.contactPhoto.setImageBitmap(getContactsImage(realmPhoneCallLogs.getNumber()));
String path = new String(Environment.getExternalStorageDirectory() + "/NewCallLogs/" + realmPhoneCallLogs
.getCallRecords());
File file = new File(path);
String size;
long filesize = file.length();
long fileSizeInKB = filesize / 1024;
long fileSizeInMB = fileSizeInKB / 1024;
if(fileSizeInKB >= 1024) {
size = fileSizeInMB + " Mb";
} else {
size = fileSizeInKB + " Kb";
}
if(!size.isEmpty()) {
viewHolder.fileSize.setText(size);
} else {
viewHolder.fileSize.setText(0);
}
if("I".equals(realmPhoneCallLogs.getCallType())) {
viewHolder.callSymbol.setImageResource(R.mipmap.call_received);
} else if("O".equals(realmPhoneCallLogs.getCallType())) {
viewHolder.callSymbol.setImageResource(R.mipmap.call_made);
} else if("UA".equals(realmPhoneCallLogs.getCallStatus())) {
viewHolder.callSymbol.setImageResource(R.mipmap.call_missed);
}
return convertView;
}
return convertView;
}
// filtering
public void filterResults(String text) {
text = text == null ? null : text.toLowerCase().trim();
if(text == null || "".equals(text)) {
updateData(realm.where(RealmPhoneCallLogs.class).findAllSorted("id");
} else {
updateData(realm.where(RealmPhoneCallLogs.class)
.contains("number", text, Case.INSENSITIVE)
.findAllSorted("id"));
}
}
public Filter getFilter() {
return new MyNamesFilter(this);
}
private class MyNamesFilter
extends Filter {
private final MyNamesAdapter adapter;
private MyNamesFilter(MyNamesAdapter 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());
}
}
}
For filtering Realm, you can also check out the official documentation on queries.
Filtering in RealmRecyclerViewAdapter does not hide excluded elements
I don't really know if this is the way to go for this problem, but it's now behaving as expected so I'll share the solution here.
Inside the HabitCardAdapter
I added another OrderedRealmCollection<Habit>
member, called filteredList
, while list
holds the whole data. In the costructor both of filteredList
and list
are tied to the data passed to the constructor, but while filteredList
will be modified by the query, list
will not (probably putting it to final
is the best practice). Then everything in the Adapter
will now reference to filteredList
instead of list
, and when the SearchView
is selected and the query is up, filteredList
will get the data, and then updateData(filteredList)
will be called.
Here is what I changed:
public class HabitCardAdapter extends RealmRecyclerViewAdapter<Habit, HabitCardAdapter.ViewHolder> implements Filterable {
Context ct;
OrderedRealmCollection<Habit> list;
OrderedRealmCollection<Habit> filteredList;
Realm mRealm;
...
}
public HabitCardAdapter(@Nullable OrderedRealmCollection<Habit> data, Context context, Realm realm) {
super(data, true, true);
ct = context;
list = data;
filteredList = data;
mRealm = realm;
setHasStableIds(true);
}
Probably the error was here in getItemCount()
, when the filteredList
size was smaller than the list
one, but since I didn't have any reference to filteredList
, I didn't have any way to change that size, and so the Adapter
would continue to show - for example - 6 views while I was querying for 3. Having it as a properly class member it let me make this:
@Override
public int getItemCount() {
return this.filteredList.size();
}
public void filterResults(String text) {
text = text == null ? null : text.toLowerCase().trim();
if (text == null || "".equals(text)) {
filteredList = list;
} else {
filteredList = mRealm.where(Habit.class).beginsWith("title", text, Case.INSENSITIVE).sort("id").findAll();
}
updateData(filteredList);
}
how to implement filterable in RealmRecyclerViewAdapter
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());
}
}
}
Search View in Realm Recycler View Android
Your code looks good just one mistake though
You are filtering result and storing too like below
filteredModelList = new ArrayList<>();
for (MyColleagueModel model : models) { final String text = model.getName().toLowerCase().toString(); if (text.contains(query)) { filteredModelList.add(model); } }
how filter list that add some filter and remove some in Realm java query
You need to store all the filters somewhere:
private List<TagPojo> filters = new ArrayList<>();
@Override
public void onFilterSelected(TagPojo item) {
filters.add(item);
String[] filterIds = filters.stream().map(f -> f.getId()).toArray(size -> new String[size]);
UpdateStuffList(list.where()
.in("tagList.id", filterIds )
.findAllAsync());
}
@Override
public void onFilterDeselected(TagPojo item) {
// need to have a proper TagPojo.equals() for this
filters.remove(item);
}
Filtering in Realm database - findAll doesn't work for query containing boolean
favourites = realm.where(MyObject.class)
.beginGroup() // <--
.equalTo("isFavourite", true)
.endGroup() // <--
.beginGroup() // <--
.contains("name", search.toString(), Case.INSENSITIVE)
.or()
.contains("category", search.toString(), Case.INSENSITIVE)
.or()
.contains("description", search.toString(), Case.INSENSITIVE)
.endGroup() // <--
.findAll();
Searchable Spinner combined with Realm
You have to be careful when you deal with realmresults across threads. The realm results from one thread you can't use in some other. So try to get a copy of your result set (Which is detached from active realm instance) and give this copy to your adapter. Realm has copyFromRealm
method for doing this.
Modify your code like this
Realm realm = Realm.getDefaultInstance();
RealmResults<MaterialDoc> realmResults = realm.where(MaterialDoc.class).findAll();
List<MaterialDoc> documents = realm.copyFromRealm(realmResults);
ArrayAdapter<MaterialDoc> adapter = new ArrayAdapter<>(this.getContext(), android.R.layout.simple_list_item_1, documents);
matList.setAdapter(adapter);
Related Topics
Android - Navigation View Item Menu Background Color
How to Raise a Toast in Asynctask, I am Prompted to Used the Looper
How to Set Delay in Android Onclick Function
Android - Detecting Application Launch from Home or History
Embed Activity Feed of a Public Facebook Page Without Forcing User to Login/Allow
Calledfromwrongthreadexception
Don't Collapse Toolbar When Recyclerview Fits the Screen
Why There's a Separate Mutablelivedata Subclass of Livedata
Android Toolbar: Small Title Text in Landscape Mode
Get Last Inserted Value from SQLite Database Android
Wrong Fragment in Viewpager Receives Oncontextitemselected Call
Mpandroidchart - Adding Labels to Bar Chart
Android 2.1 View's Getdrawingcache() Method Always Returns Null
Sdcard Content Exist But Cant See Them
Android Facebook Authorization - Can Not Log in When Official Facebook App Is Installed
Achartengine - Can't Figure How to Use Dates as X Axis - the File I Save Is Empty