How to sort recyclerview by lowest number / String Android Studio
There are some options for implementing sorting in a RecyclerView
. Of course it is possible to rely on Comparable<T>
and Comparator<T>
interfaces but, as you mentioned, it is also possible to exploit SortedList<T>
class defined in Android SDK.
Purpose of SortedList<T>
is simplifying sorting of elements in a RecyclerView
, allowing you to intercept significant events like "new item added", "item removed" and so on.
In your case you can proceed as follows:
Define a Person class for wrapping rank and name. Please notice that in this version I'm assuming to have integer values for rank, but it's quite easy to move to decimal value.
class Person { private String rank; private String name; public Person(String rank, String name) { this.rank = rank; this.name = name; } // getters and setters here }
Define an Activity where to build
RecyclerView
and corresponding adapter. In this example I've included aFloatingActionButton
for inserting new random Persons. As you can see, when creating a newPerson
, methodaddPerson
is invoked on the adapter. Its effect will be to update theRecyclerView
, sorting it according to criteria defined within the adapter itself (see point 3).public class SortPersonsActivity extends AppCompatActivity { private List<Person> mPersons; private SortPersonsAdapter mPersonsAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_persons_list); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); mPersons = new ArrayList<>(); mPersons.add(new Person("1\nrank", "James Kub")); mPersons.add(new Person("2\nrank", "Peter Hanly")); mPersons.add(new Person("3\nrank", "Josh Penny")); mPersons.add(new Person("1\nrank", "Danny Jackson")); mPersons.add(new Person("3\nrank", "Brad Black")); RecyclerView recyclerView = (RecyclerView) findViewById(R.id.lst_items); recyclerView.setLayoutManager(getLayoutManager()); mPersonsAdapter = new SortPersonsAdapter(this, mPersons); recyclerView.setAdapter(mPersonsAdapter); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // building new fake person Person person = new Person( buildRandomInt(10) + "\nrank", buildRandomName(5) + " " + buildRandomName(5)); // let's keep also basic list updated mPersons.add(person); // let's update adapter mPersonsAdapter.addPerson(person); } }); } private RecyclerView.LayoutManager getLayoutManager() { LinearLayoutManager llm = new LinearLayoutManager(this); llm.setOrientation(LinearLayoutManager.VERTICAL); return llm; } // support method for random names and ranks here }
Implement a RecyclerView Adapter relying on
SortedList<Person>
. Here it's important to notice that all Persons are inserted into aSortedList<Person>
. Creating aSortedList<T>
requires aCallback
to be defined for intercepting events as well as for defining sorting criteria. In our case, as you can see,compare
method defines criteria for sorting Persons whileonInserted
method defines what to do when a new Person is inserted (notify a data set change for updatingRecyclerView
in this case). Please notice also implementation ofaddPerson
method described at point 2. It just adds a Person to theSortedList
, because the logic for updatingRecyclerView
is embedded into theCallback
methodonInserted
mentioned before.class SortPersonsAdapter extends RecyclerView.Adapter<SortPersonsAdapter.PersonViewHolder> { protected static class PersonViewHolder extends RecyclerView.ViewHolder { View layout; TextView txt_rank; TextView txt_full_name; public PersonViewHolder(View itemView) { super(itemView); layout = itemView; txt_rank = (TextView) itemView.findViewById(R.id.txt_rank); txt_full_name = (TextView) itemView.findViewById(R.id.txt_full_name); } } private Context mContext; private LayoutInflater mLayoutInflater; private SortedList<Person> mPersons; public SortPersonsAdapter(Context context, List<Person> persons) { mContext = context; mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mPersons = new SortedList<>(Person.class, new PersonListCallback()); mPersons.addAll(persons); } public void addPerson(Person person) { mPersons.add(person); } @Override public int getItemCount() { return mPersons.size(); } @Override public SortPersonsAdapter.PersonViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = mLayoutInflater.inflate(R.layout.view_person_item, parent, false); return new PersonViewHolder(itemView); } @Override public void onBindViewHolder(final PersonViewHolder viewHolder, final int position) { Person person = mPersons.get(position); viewHolder.txt_rank.setText(person.getRank()); viewHolder.txt_full_name.setText(person.getName()); } /** * Implementation of callback for getting updates on person list changes. */ private class PersonListCallback extends SortedList.Callback<Person> { @Override public int compare(Person p1, Person p2) { String[] rank1 = p1.getStringRank().split("\n"); String[] rank2 = p2.getStringRank().split("\n"); int diff = Integer.parseInt(rank1[0]) - Integer.parseInt(rank2[0]); return (diff == 0) ? p1.getName().compareTo(p2.getName()) : diff; } @Override public void onInserted(int position, int count) { notifyItemInserted(position); } @Override public void onRemoved(int position, int count) { notifyItemRemoved(position); } @Override public void onMoved(int fromPosition, int toPosition) { } @Override public void onChanged(int position, int count) { } @Override public boolean areContentsTheSame(Person oldItem, Person newItem) { return false; } @Override public boolean areItemsTheSame(Person item1, Person item2) { return false; } } }
Hope this could help. Here I've put an implementation for your RecyclerView
, in case you need more details on code.
public int compare(Person p1, Person p2) {
if(p1.getRank() == p2.getRank()){
return p1.getName().compareTo(p2.getName());
}else if(p1.getRank() > p2.getRank()){
return 1;
}else{
return -1;
}
}
The sorting depends upon what comparison result is returned. You need to return -1
, 0
, or 1
. In the code snippet, all I am doing is checking the ranks first. If they are the same rank, I compare their names which are String
s and every String
has a compareTo( )
which lexicographically compares two strings.
If not, we just sort them based on rank.
You can simplify your compare( )
method further by making your Person
class implement Comparable
interface. That will allow you to use Collections
framework goodies out of the box.