I have a recyclerview in my app, that contains two textviews, one is rankTextView and other is nameTextview. Something like this;
What I want to do is sort this recyclerview, firstly in lowest number order and if there is two same numbers then I want it to be sorted out by Strings. In the above screenshot I have for example, two people rank 1, firstly I want the recyclerview to put these to the top and then sort it out by String.
I have searched online to see how can I go about doing this but being new to android I haven't been able to play around/adapt the findings into my project. For example;
How to sort Strings on an Android RecyclerView?
What is the SortedList<T> working with RecyclerView.Adapter?
I have created a custom adapter that contains a textview called rankTextview and another textview called nameTextview, like this;
rankTextview = (TextView) itemView.findViewById(R.id.ranktextview);
nameTextview = (TextView) itemView.findViewById(R.id.nametextview);
then I have a method that takes what value to put in these textview as parameter, like this;
public addPerson(String rankTextview, String personTextview,) {
this.rankTextview = rankTextview;
this.personTextview = personTextview;
}
and then I call this method in my main class to add data, like this;
person.add(new addPerson
("1\nrank", "James Kub"));
person.add(new addPerson
("2\nrank", "Peter Hanly"));
person.add(new addPerson
("3\nrank", "Josh Penny"));
person.add(new addPerson
("1\nrank", "Danny Jackson"));
person.add(new addPerson
("3\nrank", "Brad Black"));
Now what I want to do is sort out this data firstly by rank lowest number order e.g 1, 2,3... and if there are two same numbers then I want to sort out by name alphabetical order. Also, in future my app will contain points in stead of ranks which will be decimal numbers like this. 1.1, 1.5, 1.1, 2.1, 2.5 and so on, so would it possible to take in count decimal numbers when sorting out by rank.
Also, since I had so many lines of code, I wasn't sure which section to provide and which not to provide, please let me know if there is any code I am missing that I should have included.
EDITED:
public void animateTo(List<ExampleModel> models) {
applyAndAnimateRemovals(models);
applyAndAnimateAdditions(models);
applyAndAnimateMovedItems(models);
}
private void applyAndAnimateRemovals(List<ExampleModel> newModels) {
for (int i = mModels.size() - 1; i >= 0; i--) {
final ExampleModel model = mModels.get(i);
if (!newModels.contains(model)) {
removeItem(i);
}
}
}
private void applyAndAnimateAdditions(List<ExampleModel> newModels) {
for (int i = 0, count = newModels.size(); i < count; i++) {
final ExampleModel model = newModels.get(i);
if (!mModels.contains(model)) { // error here, saying cannot resolve method contains
addItem(i, model);
}
}
}
private void applyAndAnimateMovedItems(List<ExampleModel> newModels) {
for (int toPosition = newModels.size() - 1; toPosition >= 0; toPosition--) {
final ExampleModel model = newModels.get(toPosition);
final int fromPosition = mModels.indexOf(model);
if (fromPosition >= 0 && fromPosition != toPosition) {
moveItem(fromPosition, toPosition);
}
}
}
public ExampleModel removeItem(int position) {
final ExampleModel model = mModels.remove(position); // Error here, saying in sortedlist cannot be applied to (int)
notifyItemRemoved(position);
return model;
}
public void addItem(int position, ExampleModel model) {
mModels.add(position, model); // Error here, saying add has private access in 'android.support.v7.util.SortedList'
notifyItemInserted(position);
}
public void moveItem(int fromPosition, int toPosition) {
final ExampleModel model = mModels.remove(fromPosition); // Error here, saying in sortedlist cannot be applied to (int)
mModels.add(toPosition, model); // Error here, saying add has private access in 'android.support.v7.util.SortedList'
notifyItemMoved(fromPosition, toPosition);
}
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 a FloatingActionButton
for inserting new random Persons. As you can see, when creating a new Person
, method addPerson
is invoked on the adapter. Its effect will be to update the RecyclerView
, 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 a SortedList<Person>
. Creating a SortedList<T>
requires a Callback
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 while onInserted
method defines what to do when a new Person is inserted (notify a data set change for updating RecyclerView
in this case). Please notice also implementation of addPerson
method described at point 2. It just adds a Person to the SortedList
, because the logic for updating RecyclerView
is embedded into the Callback
method onInserted
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With