Reputation: 1110
I have a class LocationComparator
, which looks like this:
public class LocationComparator implements Comparator<MyLocation> {
double mLatitude, mLongitude;
public LocationComparator(double baseLat, double baseLon){
mLatitude = baseLat;
mLongitude = baseLon;
}
@Override
public int compare(MyLocation o, MyLocation o2) {
float[] result1 = new float[3];
android.location.Location.distanceBetween(mLatitude, mLongitude, o.latitude, o.longitude, result1);
Float distance1 = result1[0];
float[] result2 = new float[3];
android.location.Location.distanceBetween(mLatitude, mLongitude, o2.latitude, o2.longitude, result2);
Float distance2 = result2[0];
return distance1.compareTo(distance2);
}
}
Next, I have List<MyLocation> locations
and I want to sort it. I use this code:
Collections.sort(locations, new LocationComparator(baseLat, baseLon));
where baseLat
and baseLon
is latitude and longitude of current position. Sometimes, the code throws an exception java.lang.IllegalArgumentException: Comparison method violates its general contract!
.
I know, that this exception is thrown in case that compare
method does not satisfy the condition of transitivity. I found some information here: Comparison method violates its general contract!. I understand why the exception is thrown in referenced issue, but still I don't know why exception is thrown in my code.
Could you help me, please? Thanks.
UPDATE
List of MyLocation
is used for adapter for ListView
. In case, that there is a new GPS location, data in ListView
are sorted. The code looks like this:
@Override
public void onLocationChanged(Location location) {
super.onLocationChanged(location);
sortAdapter(new LatLng(location.getLatitude(), location.getLongitude()));
mIsSortedByLocation = true;
}
}
And sortAdapter(LatLng latLng)
method is here:
private void sortAdapter(LatLng latLng) {
if (mAdapter == null || latLng == null) {
return;
}
List<MyLocation> list = Arrays.asList(mAdapter.getItems());
Collections.sort(locations, new LocationComparator(latLng.latitude, latLng.longitude));
mAdapter.setItems(mMyLocations = (MyLocation[]) list.toArray());
}
UPDATE 2
The data comes from server. First, data are stored into the database, and then, there is a my ContentProvider
and Loader
. In onLoadFinished(Loader<Cursor> loader, Cursor cursor
), the data from cursor
are stored into the array
and this array
is used for creating an adapter
, which extends from BaseAdapter
.
Upvotes: 0
Views: 314
Reputation: 23972
Without knowing details of your code, I would assume that your problem comes from concurrency.
List<MyLocation> list = Arrays.asList(mAdapter.getItems());
Collections.sort(locations, new LocationComparator(latLng.latitude, latLng.longitude));
It's either typo in your example, or locations
reference is indeed populated outside of the method scope. So, I assume you're loading it from the server. Or it might very well be that you're modifying contents of Adapter
from the background thread.
Avoid changing data from background thread which is used by the main thread. So, you must either synchronize on your collection before using it or just pass the result from background thead to main thread Handler
:
List<MyLocation> locations;
void myBackgroundTask() {
List<MyLocation> result = getLocationsFromServer();
runOnUiThread(() -> { locations = result }); // lambda or Runnable
}
Upvotes: 1