0

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;

}

Community
  • 1
  • 1
Ulla
  • 70
  • 9
  • In what order? crescent? As in The Crescent Order is an organization located in Japan that protects the Lotus, an elixir that counters the effects of the Lazarus Pit? – Renats Stozkovs Mar 02 '17 at 01:30
  • 1
    Are you sure you populate the Evento.date? Because it is your custom field, not inherited from `GregorianCalendar` object – Renats Stozkovs Mar 02 '17 at 01:34

1 Answers1

1

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.

Community
  • 1
  • 1
MikaelF
  • 3,518
  • 4
  • 20
  • 33
  • You mean that I shouldn't have used the argument 'date'? But how do I atribute a GregorianCalendar value to my object Evento?@MikaelF I changed this : {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; } For this: – Ulla Mar 02 '17 at 18:26
  • @Ulla use Envento exactly the way you would use a GregorianCalendar. That's the whole point of polymorphism (and inheritance). – MikaelF Mar 02 '17 at 18:28
  • I changed this : evento.date = day; for this : evento.set(day.YEAR, day.MONTH, day.DAY_OF_MONTH); but its still not doing the sort. how is the best way to populate Evento? – Ulla Mar 02 '17 at 18:33
  • I"m new in coding and get little lost in this polymorphism sometimes – Ulla Mar 02 '17 at 18:35
  • Your Evento *is* a GregorianCalendar. That's what *extends* means. This is also why you can directly compare two instances of Evento. Look up polymorphism online (youtube is good for that), you might just be missing a few notions. – MikaelF Mar 02 '17 at 18:47
  • Well I tried whithout extending my Evento object, and it did work for listEventos2 but not for listEventos1 I'm sure missing something when populating listEventos1, I have tried many ways but don't get a clue. I will edit my question to post it. – Ulla Mar 02 '17 at 22:42
  • Now it makes sense... Sorry that I took so long time to see it and answer ... Coding is like a hobby for me... and I was little busy with other things. – Ulla May 13 '17 at 16:23