J'ai commencé à utiliser rxjava avec mes projets Android. J'ai besoin de trier la liste des événements de retour depuis un appel api. J'ai écrit une classe de comparaison pour trier la liste:
public class EventParticipantComparator {
public static class StatusComparator implements Comparator<EventParticipant> {
@Override
public int compare(EventParticipant participant1, EventParticipant participant2) {
return participant1.getStatus() - participant2.getStatus();
}
}
}
Je peux utiliser cette classe avec la classe Collections classique.
Collections.sort(participants, new EventParticipantComparator.StatusComparator());
comment puis-je réaliser cette situation de manière réactive? également s'il existe un moyen de trier la liste de manière asynchrone, je préférerai cette méthode.
Manière réactive sans liste de tri:
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) {
}
});
Si je n'avais pas lu le Javadoc pour Collections.sort()
, j'aurais recommandé quelque chose comme map
(list -> Collections.sort (list, comparator))
Pour convertir dans un tableau trié; ici, map
est le mappeur observable.
Cependant, la méthode sort
ci-dessus est un algorithme de tri sur place, qui affecte le tableau sous-jacent plutôt que de renvoyer le tableau entièrement trié. Vous devriez donc faire quelque chose comme ceci:
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.
});
Cela triera chaque List<EventParticipant>
Entrant individuellement et de manière asynchrone.
Cette solution est similaire à la réponse acceptée, mais utilise des opérateurs Rx pour 1) diviser le tableau en objets 2) trier par les instances Implémentation comparable 3) le faire sur un thread de calcul dédié;
dataManager.getEventImplementer().getParticipants(event.getId())
.flatMap(Observable::from)
.toSortedList()
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(sortedList -> {...}, error -> {...});
Notez qu'il est préférable d'utiliser Schedulers.io pour les écritures réseau/disque, Schedulers.computation pour les calculs comme le tri
Je suppose que la méthode getParticipants()
renvoie Observable<List<EventPartcipant>>
.
Dans l'extrait ci-dessous, je convertis d'abord le Observable<List<EventPartcipant>>
En Observable<EventParticipant>
À l'aide de l'opérateur flatMap()
. Cet observable émettra chaque EventParticipant
un à la fois. Maintenant, en utilisant l'opérateur toSortedList()
, je peux agir sur deux EventParticipant
objets à la fois comme le prévoit Comparator<EventParticipant>::compareTo
.
Dans les autres solutions, les opérateurs de tri sont appliqués après .observeOn(AndroidSchedulers.mainThread())
, ce qui signifie que le tri réel se produit sur le thread d'interface utilisateur.
J'ai modifié cela pour laisser l'appel d'API s'exécuter sur le planificateur IO, le tri sur le planificateur de calcul et enfin votre liste triée sur le thread d'interface utilisateur.
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.
}
});
Il existe également une autre façon de trier la liste
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.
});
Version 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 ->
//..
}))
Vous pouvez également faire comme ceci:
Observable.from(list)
.sorted((o1, o2) -> o1.name.compareTo(o2.name))
.toList()
.subscribe(
sortedList -> sortedList,
error -> error);
Kotlin:
list.sortBy { it.name }