android - Filtering in RecyclerView takes long -
i testing set of 5000 objects. use custom comparator(myownsort) sort values based on business logic.
public filter getfilter() { if (_filter == null) { _filter = new filter() { @override protected filterresults performfiltering(charsequence constraint) { string chartext = constraint.tostring(); filterresults filterresults = new filterresults(); // clear data visibledata.clear(); (string title : data) { if (title.startswith(chartext)) { visibledata.add(title); } } myownsort.setsearchstring(chartext); collections.sort(visibledata, myownsort); } filterresults.count=visibledata.size(); filterresults.values=visibledata; return filterresults; } @override protected void publishresults (charsequence constraint, filterresults results){ notifydatasetchanged(); } } ; } return _filter;
}
this takes somewhere between 200 1600ms depending on android device. takes long when start typing filter data data filtered large. keep typing more, dataset narrows down , faster. see, performfiltering ran in background thread, not block ui thread. results don't show not snappy. normal? there can improve this? if not how can make experience better? edit: added customcomparator class.
class customcomparator implements comparator<string> { private string _searchstring; public customsearchstringcomparator(string searchstring) { _searchstring = searchstring; } public void setsearchstring(string searchstring) { _searchstring = searchstring; } @override public int compare(string lhs, string rhs) { int res = customcompare(lhs, rhs); // alphabetic if (res == 0) { res = alphacompare(lhs, rhs); } return res; } private int customcompare(string lhs, string rhs) { string lhstitle = lhs.tolowercase(locale.getdefault()); string rhstitle = rhs.tolowercase(locale.getdefault()); string[] lhsnames = lhstitle.split("\\s+"); string lhsfirstname = lhsnames[0]; string lhslastname = lhsnames.length > 1 ? lhsnames[1] : ""; // if there middle name... if (lhsnames.length > 2) { lhslastname = lhsnames[2]; } string[] rhsnames = rhstitle.split("\\s+"); string rhsfirstname = rhsnames[0]; string rhslastname = rhsnames.length > 1 ? rhsnames[1] : ""; // if there middle name... if (rhsnames.length > 2) { rhslastname = rhsnames[2]; } boolean lhsfirstnamecontains = lhsfirstname.startswith(_searchstring); boolean rhsfirstnamecontains = rhsfirstname.startswith(_searchstring); boolean lhslastnamecontains = lhslastname.startswith(_searchstring); boolean rhslastnamecontains = rhslastname.startswith(_searchstring); if (lhsfirstnamecontains == rhsfirstnamecontains) { if (lhslastnamecontains == rhslastnamecontains) { return 0; } else { return rhslastnamecontains ? 1 : -1; } } else { return rhsfirstnamecontains ? 1 : -1; } } private int alphacompare(string lhs, string rhs) { return string.case_insensitive_order.compare(lhs, rhs); }
split("\s+") culprit creating pattern every time regex evaluation. since needed simple split based on whitespace, used apache commons split method. basic split , faster , dramatically reduced time half.