RxJava2:在Observable中过滤List<Object>

3

我对Rx编程非常陌生,但我正在尝试在项目中使用它。我的目标是拥有一个GamesInfoList对象,如下所示:

@AutoValue
public abstract class GameInfoList {
    public static TypeAdapter<GameInfoList> typeAdapter(Gson gson) {
        return new AutoValue_GameInfoList.GsonTypeAdapter(gson);
    }

    public static Builder builder() {
        return new AutoValue_GameInfoList.Builder();
    }

    public abstract long id();

    @Nullable
    public abstract String date_added();

    @Nullable
    public abstract String date_last_updated();

    @Nullable
    public abstract GameImages image();

    @Nullable
    public abstract String name();

    @Nullable
    public abstract List<GamePlatformInfo> platforms();

    @AutoValue.Builder
    public abstract static class Builder {

        public abstract Builder id(long id);

        public abstract Builder date_added(String date_added);

        public abstract Builder date_last_updated(String date_last_updated);

        public abstract Builder image(GameImages image);

        public abstract Builder name(String name);

        public abstract Builder platforms(List<GamePlatformInfo> platforms);

        public abstract GameInfoList build();
    }
}

现在,我想按照日期和名称加载我的游戏,并编写了一个方法来访问上述对象。

public void loadGamesByDateAndName(String date, String name) {
    Timber.d("Load games by date: " + date + " and name: " + name);
    remoteDataHelper
            .getGamesListByDate(date)
            .flatMapObservable(Observable::fromIterable)
            .filter(game -> game.platforms() != null)
            .filter(game -> game.platforms().name().contains(name))
            .toList()
            .subscribe(getObserverFiltered(name, false));
}

在这里,我正在使用filter()运算符过滤基于此方法中输入的名称的平台对象。上述方法显示错误,因为平台是列表类型。我该如何通过列表进行过滤以匹配名称并在我的Android应用程序中显示?为了按日期和名称加载数据,需要对上述方法进行哪些更改?

2个回答

3
最简单的方法是在第二个filter操作符内部进行迭代。
public void loadGamesByDateAndName(String date, String name) {
    Timber.d("Load games by date: " + date + " and name: " + name);
    remoteDataHelper
            .getGamesListByDate(date)
            .flatMapObservable(Observable::fromIterable)
            .filter(game -> game.platforms() != null)
            .filter(game -> { for(GamePlatformInfo platform : game.platforms()){
                                  if(platform.name().contains(name)) {
                                      return true;
                                  }
                              }
                              return false;
                    }
            )
            .toList()
            .subscribe(getObserverFiltered(name, false));
}

我猜这应该可以很好地工作,因此我会接受这个答案。稍后会进行测试。非常感谢!!! :-) - Nithin Prasad
1
有时候最简单的解决方案是最好的。也许你可以构建更加RXy和聪明的东西,但最终它只会更难为下一个阅读它的人或者一个月后的你所理解。 ;) - kenny_k
是的,我想是这样。运算符很难记住。我想在很多项目中都需要使用它们。 - Nithin Prasad
哈哈,为什么三年后才拒绝呢?有更好的方法吗?如果有,请发布为答案,我会很高兴地点赞。 - kenny_k
1
抱歉 @kenny_k,可能是我不小心误操作了。重新接受它。 - Nithin Prasad

-1

你需要在 GamePlatformInfo 类中重写 equals() 方法。

我假设你有以下的 GamePlatformInfo 类定义:

class GamePlatformInfo{
    String name;
    ...
    ...

    public GamePlatformInfo(String name){
        this.name = name;
        ...
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) return true;
        if (!(o instanceof GamePlatformInfo)) return false;
        final GamePlatformInfo other = (GamePlatformInfo)o;
        return name.equals(other.name);
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + name.hashCode();
        return result;
    }
}

然后,您只需要使用contains()运算符来搜索该列表。 请检查以下修改后的片段:

public void loadGamesByDateAndName(String date, String name) {
    Timber.d("Load games by date: " + date + " and name: " + name);
    remoteDataHelper 
            .getGamesListByDate(date) 
            .flatMapObservable(Observable::fromIterable) 
            .filter(game -> game.platforms() != null) 
            .filter(game -> game.platforms().contains(new GamePlatformInfo(name))) // This is all you need to do to search through the list.
            .toList() 
            .subscribe(getObserverFiltered(name, false));
} 

在幕后:如果您创建了一个覆盖了equals()方法的类的列表,那么list.contains()方法将使用给定的equals定义来比较列表项。
希望这可以帮助到您。

这是不正确的。List#contains 方法使用类的 equals 方法进行比较,而不是 compareTo,如此文档所述 here。为了这个特定的用例而覆盖你的类的 equals 方法是一个非常糟糕的想法,因为它可能会在其他地方引起问题。 - kenny_k
@theFunkyEngineer 你说得对。Comparable 用于排序,我已经纠正了答案。重写 equals 并不是一个坏主意,如果你正确实现它,不会破坏任何东西。看一下 equals() 实现。即使在使用列表时,也要遵循最佳实践,不要盲目地使用 for 循环迭代列表。 - Sachin Chandil
@theFunkyEngineer 在 RxJava 中,打破你已经完成的 Observable 链来搜索列表并不是最佳实践。我不是说你错了,但这才是惯用代码应该编写的方式。没有冒犯之意,谢谢理解。 - Sachin Chandil
如果你不小心的话,重写equals可能会有风险 - 因为它没有重写hashCode,而这是必须的。此外,这样做会为整个系统强制实施某些对象使用规则,仅仅是为了方便单个用例,我认为这可能会带来麻烦。例如,如果该对象最终进入任何ORM或其他序列化库中,等等。 - kenny_k
另外,如果您发现我的答案有问题,请直接在那里评论,我很乐意进行讨论,这样我们就可以避免线程纠缠 :) - kenny_k
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接