Список сортировки android rxjava с классом компаратора

Я начал использовать rxjava с моими проектами Android. Мне нужно отсортировать список событий из вызова api. Я написал класс компаратора для сортировки списка:

public class EventParticipantComparator {

    public static class StatusComparator implements Comparator<EventParticipant> {

        @Override
        public int compare(EventParticipant participant1, EventParticipant participant2) {
            return participant1.getStatus() - participant2.getStatus();
        }
    }
}

Я могу использовать этот класс с классическим классом Collections.

Collections.sort(participants, new EventParticipantComparator.StatusComparator());

Как я могу достичь этой ситуации реактивным способом? также, если есть какой-либо способ сортировки списка асинхронно, я предпочитаю этот путь.

Реактивный путь без списка сортировки:

dataManager.getEventImplementer().getParticipants(event.getId())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<List<EventParticipant>>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(List<EventParticipant> eventParticipants) {

                    }
                });

Ответ 1

Если бы я не читал Javadoc для Collections.sort(), я бы рекомендовал нечто вроде map (list → Collections.sort(list, comparator)) чтобы преобразовать его в отсортированный массив; здесь map является наблюдаемым преобразователем.

Однако метод sort выше - это алгоритм сортировки на месте, который влияет на базовый массив, а не возвращает полностью отсортированный массив. Поэтому вместо этого вы должны сделать что-то вроде этого:

dataManager.getEventImplementer().getParticipants(event.getId())
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .map(unsortedList -> {
                List<EventParticipant> sortedList = new ArrayList<>(unsortedList);
                Collections.sort(sortedList, new EventParticipantComparator.StatusComparator());
                return sortedList;
            })
            .subscribe(new Subscriber<List<EventParticipant>>() {
                // ... etc.
            });

Это сортирует каждый входящий List<EventParticipant> индивидуально и асинхронно.

Ответ 2

Это решение похоже на принятый ответ, но использует операторы Rx для 1) разбиения массива на объекты; 2) сортировки по экземплярам; сопоставимой реализации; 3) делать это по выделенному потоку вычислений;

dataManager.getEventImplementer().getParticipants(event.getId())
    .flatMap(Observable::from)
    .toSortedList()
    .subscribeOn(Schedulers.computation())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(sortedList -> {...}, error -> {...});

Обратите внимание, что он предпочитает использовать Schedulers.io для записи в сети/диске, Schedulers.computation для вычислений, таких как сортировка

Ответ 3

Я предполагаю, что метод getParticipants() возвращает Observable<List<EventPartcipant>>.

В приведенном ниже фрагменте я сначала конвертирую Observable<List<EventPartcipant>> в Observable<EventParticipant> с помощью оператора flatMap(). Этот наблюдаемый будет излучать каждый EventParticipant по одному за раз. Теперь, используя оператор toSortedList(), я могу воздействовать на два объекта EventParticipant одновременно, как ожидается, Comparator<EventParticipant>::compareTo.

В других решениях операторы сортировки применяются после .observeOn(AndroidSchedulers.mainThread()), что означает, что фактическая сортировка происходит в потоке пользовательского интерфейса.

Я изменил это, чтобы вызов API выполнялся в планировщике ввода-вывода, сортировки в планировщике вычислений и, наконец, ваш отсортированный список в потоке пользовательского интерфейса.

getParticipants().flatMap(new Func1<List<EventParticipant>, Observable<EventParticipant>>() {
        @Override
        public Observable<EventParticipant> call(List<EventParticipant> eventParticipants) {
            return Observable.from(eventParticipants);
        }
    }).subscribeOn(Schedulers.io())
      .observeOn(Schedulers.computation())
      .toSortedList(new Func2<EventParticipant, EventParticipant, Integer>() {
                @Override
                public Integer call(EventParticipant eventParticipant, EventParticipant eventParticipant2) {
                    return new StatusComparator().compare(eventParticipant, eventParticipant2);
                }
    }).observeOn(AndroidSchedulers.mainThread())
      .subscribe(new Action1<List<EventParticipant>>() {
                @Override
                public void call(List<EventParticipant> eventParticipants) {
                    // Your sorted list on UI thread.
                }
    });

Ответ 4

Существует также еще один способ сортировки списка

dataManager.getEventImplementer().getParticipants(event.getId())
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .flatMapIterable(participants -> participants)
        .toSortedList((p1,p2) -> {p1.getStatus() - p2.getStatus()})
        .subscribe(new Subscriber<List<EventParticipant>>() {
            // ... etc.
        });

Ответ 5

Kotlin версия:

disposable.add(interactor.getItemList() //It returns Observable<ItemListResponseModel>
    .compose(threadTransformer.applySchedulers())
    .flatMapIterable { list -> list }
    .toSortedList { p1, p2 ->
        (p1?.name ?: "").compareTo(p2?.name ?: "")
    }
    .subscribe({ items ->
        //...
    }, { throwable ->
        //..
    }))