带有比较器类的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 -&gt; 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&lt;EventParticipant&gt; 进行单独和异步排序。

【讨论】:

嗯,你的方式对我来说看起来不错。你知道 rxjava 的 toSortedList() 函数吗?如何将 StatusComparator 函数传递给 toSortedList() 函数。 如果您愿意,可以使用toSortedList(comparator)。但是,这只有在 observable 中的底层对象是 EventParticipants 而不是列表本身时才有效。你写它的方式,似乎方法getParticipants()的输出是Observable&lt;List&lt;EventParticipant&gt;&gt; 是的,getParticipants() 函数的返回值为Observable&lt;List&lt;EventParticipant&gt;&gt;。感谢您的回答。我接受你的帖子。 在你的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&lt;List&lt;EventPartcipant&gt;&gt;

在下面的 sn-p 中,我首先使用 flatMap() 运算符将 Observable&lt;List&lt;EventPartcipant&gt;&gt; 转换为 Observable&lt;EventParticipant&gt;。这个 observable 将每次发出一个 EventParticipant。现在,通过使用 toSortedList() 运算符,我可以一次对两个 EventParticipant 对象进行操作,就像 Comparator&lt;EventParticipant&gt;::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 在房间数据库中不起作用

谁来讲讲Rxjava,rxandroid中的操作符的作用

谁来讲讲Rxjava,rxandroid中的操作符的作用

谁来讲讲Rxjava,rxandroid中的操作符的作用

Android - 是不是可以使用 Comparator.comparing 而不是 API < 24 上的自定义比较器对列表进行排序?