Ulla
Ulla

Reputation: 70

Android - java - how to sort a list of object byan GregorianCalendar argument

I want to display a List of objects sorted by a date argument in crescent order. I have tried many ways. But it doesn't work. It's not changing the order of the objects in the list. I visited this for help: Android: How to sort list items according to dates

How to Sort Date in descending order From Arraylist Date in android?

https://www.quora.com/How-do-I-sort-an-ArrayList-of-objects-by-each-objects-integer-parameter

Here is my code:

my Class Object

public class Evento extends GregorianCalendar {

public Calendar date;
public String tipo = " ";
public String a = " ";
public String b = " ";
public String c = " ";

And my MainActivity:

public void implementList (View view){

    List <Evento> listEventosAll = new ArrayList<>();

    listEventosAll.addAll(listEventos1);

    listEventosAll.addAll(listEventos2);

    Collections.sort(listEventosAll,  new Comparator<Evento> (){
         public int compare(Evento evento1, Evento evento2) {
             if (evento1.date.getTime() == null || evento2.date.getTime() == null)
                 return 0;
             return evento1.date.getTime().compareTo(evento2.date.getTime());
        }

   }); 


    EventoAdapter adapter = new EventoAdapter(this,listEventosAll);
    ListView listView = (ListView) findViewById(R.id.listView);
    listView.setAdapter(adapter);
}

populating ListEventos1

public static Evento setEvento(Calendar day, String a, String b) {

Evento evento = new Evento();
evento.date = day;
evento.a = a;
evento.b = b; 
return evento;

}

// Creating the list:

public static ArrayList listEventos1(int year){

Calendar day = calculateCertainTuesday(year);

ArrayList <Evento> list = new ArrayList<Evento>();

list.add(setEvento(day, "Certain Tuesday”, "do this"));

day.add(Calendar.DAY_OF_MONTH, 1); 

list.add(setEvento(day, "Certain Wendsday”, "do that"));

day.add(Calendar.DAY_OF_MONTH,-2); 

list.add(setEvento(day, "Certain Monday", "do what"));


day.add(Calendar.DAY_OF_MONTH, -1); 

list.add(setEvento(day, "SUNDAY", "don’t do"));


return list;

}

Upvotes: 0

Views: 459

Answers (1)

MikaelF
MikaelF

Reputation: 3615

EDIT I completly overhauled my answer in response to the new edit on your question.

The problem is that for each Evento that populates your listEventos1, you're using the same Calendar (variable name day). You're doing this:

list.add(setEvento(day, "Certain Tuesday”, "do this"));

And then this:

day.add(Calendar.DAY_OF_MONTH, 1); 
list.add(setEvento(day, "Certain Wendsday”, "do that"));

But what the call to Calendar#add does is it

Adds or subtracts the specified amount of time to the given calendar field, based on the calendar's rules.

In other words, Calendar is a mutable class, i.e. it can change states, unlike a String, which is immutable and will always be the same. Don't worry, you're not the first to make that mistake, and that's partly why Java introduced a new Date API (more precisely, it's because that made the classes not thread-safe).

So in other words, whenever you're calling the Calendar#add method, all objects in listEventos1 change, because they all contain the same instance of Calendar. For a really good example of why this happens, see this answer.

One way to verify this is to add a supplementary check in your Comparator by using the == operator. == will return true if the two variables point to the same instance:

Collections.sort(listEventosAll,  new Comparator<Evento> (){
    public int compare(Evento evento1, Evento evento2) {
        if(evento1.date.getTime() == evento2.date.getTime()) 
            System.out.println("Warning! Two references pointing to the same object!");
         if (evento1.date.getTime() == null || evento2.date.getTime() == null)
             return 0;
         return evento1.date.getTime().compareTo(evento2.date.getTime());
    }

Running this with your current code should output a bunch of warnings.

Another tidbit of information: according to the Javadoc of Comparator, Comparator#compare should throw a NullPointerException if one of the arguments is null.


SOLUTION To fix this problem, you need to pass different instances of Calendar at each call of setEvento. Some classes, such as those in the Collection API possess copy constructors, that is, constructors that will take an object as an argument, and return a new object with exactly the same values. Calendar doesn't implement copy constructors, but it does however implement the Cloneable interface, which means you can clone its objects.

Cloning is sometimes frowned upon in the Java world, but in this specific case it's a viable option.

So here's how to clone day so that each time you call Evento, it points to a new object (this is your listEventos1 method):

list.add(setEvento(day, "Certain Tuesday", " do this "));
day = (Calendar) day.clone(); //This is what I added
day.add(Calendar.DAY_OF_MONTH, 1);

Naturally, repeat this for every object your insert.


NOTE: btw, some quotation marks in your code are closing English quotation marks () instead of double quotes ("). This will break your code.

OTHER NOTE: You're not using the inheritance mechanism correctly, and your code could be simplified by using Evento as a Calendar itself. But that's for another day.

Upvotes: 1

Related Questions