29

I have a listview connected to a custom array adapter. This list shows information received by a TCP connection which changes the dataSet...

I am able to sort the listview with sort (Comparator<? super T> comparator), but when the dataSet is changed, the listview is no more sorted...

I can use sort () every time the dataSet is changed, but I think this is not the best option...

How can I do that? Any suggestions?

EDIT

I am having problems in implementing the solutions presented...

MyComparatorB.java

public class MyComparatorB implements Comparator<DeviceB> {

private byte orderType;

public MyComparatorB(byte type) {

    this.orderType = type;

}

public int compare(DeviceB lhs, DeviceB rhs) {

    int res = 0;
    if (orderType == SortType.ALPHA) {
            res = (lhs.getName()).compareTo(rhs.getName());
        }
        else if (orderType == SortType.LAST_ACT) {
            res = (rhs.getTime().getTime()).compareTo(lhs.getTime().getTime());
        }
        return res;
    }

}

Snippet of my customArrayAdapter.java

    @Override
public void notifyDataSetChanged() {
    super.notifyDataSetChanged();
}


//-----------Order the content of the arrayAdapter------------//
public void sort(byte sortType) {

    super.sort(new MyComparatorB(sortType));
    notifyDataSetChanged();
}

In my MyActivity.java

myDevAdapter.sort(SortType.ALPHA);

When I am debugging, the method super.sort(new MyComparatorB(sortType)); is called and the constructor of MyComparatorB is called too. But the method compare(DeviceB lhs, DeviceB rhs) is never called and my arrayList is not sorted... What I am doing wrong?

amp
  • 11,754
  • 18
  • 77
  • 133

8 Answers8

48

I guess you need to override notifyDataSetChanged method in your adapter and perform sorting right before calling its super. See below:

@Override
public void notifyDataSetChanged() {
    //do your sorting here

    super.notifyDataSetChanged();
}

Doing so will sort the list whenever you call notifyDataSetChanged method to refresh list items. Otherwise, feed a sorted List/array to your adapter.


Or more preferably, use the sort method available in your adapter to get the job done.

adapter.sort(new Comparator<String>() {
    @Override
    public int compare(String lhs, String rhs) {
        return lhs.compareTo(rhs);   //or whatever your sorting algorithm
    }
});
waqaslam
  • 67,549
  • 16
  • 165
  • 178
  • the only way is call the `super.sort(comparator)` method every time the dataSet is changed? – amp Mar 28 '12 at 13:36
  • yes, add this before calling super.notifyDataSetChanged, so that your data is sorted everytime – waqaslam Mar 28 '12 at 13:36
  • 22
    The .sort function automatically calls notifyDataSetChanged, so if you use this code with the built-in sort, you'll get into an infinite loop and overflow your stack. Only do this if you're managing the list yourself, but most people using an Array Adapter aren't doing that. – datu-puti Aug 28 '13 at 03:30
4

This works for me

@Override
public void notifyDataSetChanged() {
    this.setNotifyOnChange(false);

    this.sort(new Comparator<String>() {
        @Override
        public int compare(String lhs, String rhs) {
            return lhs.compareTo(rhs);
        }
    });

    this.setNotifyOnChange(true);
}
KristianR
  • 420
  • 2
  • 6
4
  • Store data to an ArrayList
  • Attach Array to Adapter
  • Sort array and assign to itself
  • Use notifyDataSetChanged() to refresh Adapter
Behnam
  • 2,212
  • 2
  • 22
  • 32
1

Per elBradford's comment concerning the potential for a stack overflow resulting from the notifyDataSetChanged() approach, I ended up overriding the ArrayAdapter's add() method instead to ensure that the items maintain a sorted consistency when added one by one. (when calling addAll() I am sorting the items prior to; but I imagine you could override addAll() as well).

    @Override
    public void add(ListThing object) {
        super.add(object);
        this.sort(ListThing.sComparator);
    }
HelloImKevo
  • 547
  • 6
  • 11
0

Based on waqaslam and KristianR's answer :

@Override
public void notifyDataSetChanged() {
    this.setNotifyOnChange(false);

    this.sort(new Comparator<String>() {

        @Override
        public int compare(String s1, String s2) {
            return s1.compareTo(s2);
        }
    });

    super.notifyDataSetChanged();
    this.setNotifyOnChange(true);
}

Hope it helps.

David
  • 81
  • 2
  • 13
0

Initialize ArrayAdapter and declare that we’re converting Strings into Views

val arrayAdapter = ArrayAdapter<String>(
            requireActivity(),
            R.layout.item_sample,
            R.id.tv_item_sample,
            samplesArray
)

Set the Adapter to the ListView, using setAdapter()

binding.lvSample.adapter = arrayAdapter

Perform sort and update the adapter.

arrayAdapter.sort { lhs, rhs -> lhs!!.compareTo(rhs!!) }
arrayAdapter.setNotifyOnChange(true)
sabith.ak
  • 255
  • 4
  • 12
0

Since is the Adapter filling the ListView, the only way is to pass the data object in a sorted way.

Blackbelt
  • 156,034
  • 29
  • 297
  • 305
0

Once the listView is sorted, call adapter.notifyDataSetChanged() from your activity.

user936414
  • 7,574
  • 3
  • 30
  • 29