How to Filter the Data in Realm Adapter

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 filteredListsize 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



Leave a reply



Submit