带有比较器类的android rxjava排序列表
Posted
技术标签:
【中文标题】带有比较器类的android rxjava排序列表【英文标题】:android rxjava sort list with comparator class 【发布时间】:2017-03-09 02:54:21 【问题描述】:我开始在我的 android 项目中使用 rxjava。我需要从 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】:如果我没有阅读Collections.sort()
的Javadoc,我会推荐map
(list -> Collections.sort (list, comparator))
之类的东西将其转换为排序数组;这里,map
是 observable 映射器。
但是,上面的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>
进行单独和异步排序。
【讨论】:
嗯,你的方式对我来说看起来不错。你知道 rxjava 的 toSortedList() 函数吗?如何将 StatusComparator 函数传递给 toSortedList() 函数。 如果您愿意,可以使用toSortedList(comparator)
。但是,这只有在 observable 中的底层对象是 EventParticipant
s 而不是列表本身时才有效。你写它的方式,似乎方法getParticipants()
的输出是Observable<List<EventParticipant>>
。
是的,getParticipants()
函数的返回值为Observable<List<EventParticipant>>
。感谢您的回答。我接受你的帖子。
在你的sn-p中复制集合的原因是什么?
我不想修改通过引用传递给我们的基础列表。通常,您希望避免副作用,因为它会让使用您的代码的任何人都感到困难。我复制是为了避免这种副作用。【参考方案2】:
此解决方案类似于公认的答案,但使用 Rx 运算符来 1)将数组拆分为对象 2)按实例排序 Comparable implementation 3)在专用计算线程上执行;
dataManager.getEventImplementer().getParticipants(event.getId())
.flatMap(Observable::from)
.toSortedList()
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(sortedList -> ..., error -> ...);
请注意,最好使用 Schedulers.io 进行网络/磁盘写入,使用 Schedulers.computation 进行排序等计算
【讨论】:
是的,谢谢Schedulers.computation()
提示。
我觉得map()操作应该是flatMap()。【参考方案3】:
我假设getParticipants()
方法返回Observable<List<EventPartcipant>>
。
在下面的 sn-p 中,我首先使用 flatMap()
运算符将 Observable<List<EventPartcipant>>
转换为 Observable<EventParticipant>
。这个 observable 将每次发出一个 EventParticipant
。现在,通过使用 toSortedList()
运算符,我可以一次对两个 EventParticipant
对象进行操作,就像 Comparator<EventParticipant>::compareTo
所期望的那样。
在其他解决方案中,排序运算符应用在.observeOn(AndroidSchedulers.mainThread())
之后,这意味着实际的排序发生在UI线程上。
我对此进行了修改,让 API 调用在 IO 调度程序上执行,在计算调度程序上排序,最后在 UI 线程上排序。
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 ->
//..
))
【讨论】:
【参考方案6】:你也可以这样做:
Observable.from(list)
.sorted((o1, o2) -> o1.name.compareTo(o2.name))
.toList()
.subscribe(
sortedList -> sortedList,
error -> error);
科特林:
list.sortBy it.name
【讨论】:
以上是关于带有比较器类的android rxjava排序列表的主要内容,如果未能解决你的问题,请参考以下文章
Android RxJava 按其参数排序对象,该参数是另一个对象的列表
带有 RxJava Single 的 Android Livedata 在房间数据库中不起作用
Android - 是不是可以使用 Comparator.comparing 而不是 API < 24 上的自定义比较器对列表进行排序?