自定义筛选器运算符RxJava

自定义筛选器运算符RxJava,java,android,rx-android,rx-java2,reactive,Java,Android,Rx Android,Rx Java2,Reactive,我试图拥抱RxJava的荣耀,并将其集成到我的应用程序中。我已经为添加累积成本不超过定义预算的漫画编写了以下代码。为了实现这一点,我编写了两个实现 使用Observable.create(),这主要是因为订阅和背压的复杂性而不鼓励使用 使用RxAndroid库中已有的运算符 如果在Observable.create()中将订阅和背压处理放在一边,我很想获得关于哪个实现在性能、内存消耗和简单性方面更好的反馈 第一次实施: Observable<Integer> filterObserv

我试图拥抱RxJava的荣耀,并将其集成到我的应用程序中。我已经为添加累积成本不超过定义预算的漫画编写了以下代码。为了实现这一点,我编写了两个实现

  • 使用
    Observable.create()
    ,这主要是因为订阅和背压的复杂性而不鼓励使用
  • 使用RxAndroid库中已有的运算符
  • 如果在
    Observable.create()
    中将订阅和背压处理放在一边,我很想获得关于哪个实现在性能、内存消耗和简单性方面更好的反馈

    第一次实施:

    Observable<Integer> filterObservable = Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> e) throws Exception {
            Timber.d("filterComicsAccordingToBudget():subscribe");
            int pageCountOfComicsWithInBudget = 0;
            double totalCost = 0.0;
            for(MarvelComic comic : getMarvelComicsList()) {
                totalCost += Double.valueOf(comic.getPrice());
                Timber.d("totalCost: %s budget: %s priceOfComic: %s", totalCost, budget, comic.getPrice());
                if(totalCost > budget) {
                    break;
                }
                pageCountOfComicsWithInBudget += Integer.valueOf(comic.getPageCount());
                Timber.d("pageCount: %s price: %s comicName: %s totalPages: %s", comic.getPageCount(), comic.getPrice(), comic.getTitle(), pageCountOfComicsWithInBudget);
                e.onNext(pageCountOfComicsWithInBudget);
            }
            e.onComplete();
        }
    });
    
    filterObservable.subscribeOn(Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<Integer>() {
            int comicCount = 0;
            int pageCountOfComicsWithInBudget = 0;
    
            @Override
            public void onSubscribe(Disposable d) {
                Timber.d("filterComicsAccordingToBudget():onSubscribe");
            }
    
            @Override
            public void onNext(Integer pageCountOfComicsWithInBudget) {
                Timber.d("filterComicsAccordingToBudget():onNext");
                comicCount++;
            }
    
            @Override
            public void onError(Throwable e) {
                Timber.e("onFilterComicsForBudget:onError() %s", e);
            }
    
            @Override
            public void onComplete() {
                Timber.d("filterComicsAccordingToBudget():onComplete");
            }
        }
    });
    
    Observable.fromIterable(getMarvelComicsList())
        .map(new Function<MarvelComic, HashMap<String, Double>>() {
            HashMap<String, Double> myMap = new HashMap<String, Double>();
            double count = 0;
    
            @Override
            public HashMap<String, Double> apply(@NonNull MarvelComic marvelComic) throws Exception {
                myMap.put("price", Double.valueOf(marvelComic.getPrice()));
                myMap.put("pageCount", Double.valueOf(marvelComic.getPageCount()));
                myMap.put("comicsCount", count++);
                return myMap;
            }
        })
        .takeWhile(new Predicate<HashMap<String, Double>>() {
    
            double sum;
    
            @Override
            public boolean test(@NonNull HashMap<String, Double> map) throws Exception {
                Timber.e("sum is: %s", sum);
                return (sum += map.get("price")) < 5.00;
            }
        })
        .subscribe(new Observer<HashMap<String, Double>>() {
    
            @Override
            public void onSubscribe(Disposable d) {
            }
    
            @Override
            public void onNext(HashMap<String, Double> map) {
                Timber.e("value in onNext is: %s %s %s", map.get("pageCount"), map.get("price"), map.get("comicsCount"));
            }
    
            @Override
            public void onError(Throwable e) {
                Timber.e("onError()!!!   %s",e);
            }
    
            @Override
            public void onComplete() {
                Timber.e("onComplete()!!!");
            }
        });
    
    Observable filterObservable=Observable.create(newobservableOnSubscribe()){
    @凌驾
    public void subscribe(observeiemitter e)引发异常{
    Timber.d(“filterComicsAccordingToBudget():subscribe”);
    int pageCountOfComicsWithInBudget=0;
    双重总成本=0.0;
    for(MarvelComic:getMarvelComicsList()){
    totalCost+=Double.valueOf(comic.getPrice());
    Timber.d(“总成本:%s预算:%s成本:%s”,总成本,预算,漫画.getPrice());
    如果(总成本>预算){
    打破
    }
    pageCountOfComicsWithInBudget+=Integer.valueOf(comic.getPageCount());
    Timber.d(“页面计数:%s价格:%s comicName:%s总页面:%s”、comic.getPageCount()、comic.getPrice()、comic.getTitle()、pageCountOfComicsWithInBudget”);
    e、 onNext(micoswithinbudget的页面计数);
    }
    e、 onComplete();
    }
    });
    filterObservable.subscribeOn(Schedulers.computation())
    .observeOn(AndroidSchedulers.mainThread())
    .订阅(新观察员){
    int COMICACCOUNT=0;
    int pageCountOfComicsWithInBudget=0;
    @凌驾
    认购的公共无效(一次性d){
    Timber.d(“filterComicsAccordingToBudget():onSubscribe”);
    }
    @凌驾
    public void onNext(整数pageCountOfComicsWithInBudget){
    Timber.d(“filterComicsAccordingToBudget():onNext”);
    ComicAccount++;
    }
    @凌驾
    公共无效申报人(可丢弃的e){
    e(“预算的onfiltercomics:onError()%s”,e);
    }
    @凌驾
    未完成的公共空间(){
    Timber.d(“filterComicsAccordingToBudget():onComplete”);
    }
    }
    });
    
    第二次实施:

    Observable<Integer> filterObservable = Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(ObservableEmitter<Integer> e) throws Exception {
            Timber.d("filterComicsAccordingToBudget():subscribe");
            int pageCountOfComicsWithInBudget = 0;
            double totalCost = 0.0;
            for(MarvelComic comic : getMarvelComicsList()) {
                totalCost += Double.valueOf(comic.getPrice());
                Timber.d("totalCost: %s budget: %s priceOfComic: %s", totalCost, budget, comic.getPrice());
                if(totalCost > budget) {
                    break;
                }
                pageCountOfComicsWithInBudget += Integer.valueOf(comic.getPageCount());
                Timber.d("pageCount: %s price: %s comicName: %s totalPages: %s", comic.getPageCount(), comic.getPrice(), comic.getTitle(), pageCountOfComicsWithInBudget);
                e.onNext(pageCountOfComicsWithInBudget);
            }
            e.onComplete();
        }
    });
    
    filterObservable.subscribeOn(Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<Integer>() {
            int comicCount = 0;
            int pageCountOfComicsWithInBudget = 0;
    
            @Override
            public void onSubscribe(Disposable d) {
                Timber.d("filterComicsAccordingToBudget():onSubscribe");
            }
    
            @Override
            public void onNext(Integer pageCountOfComicsWithInBudget) {
                Timber.d("filterComicsAccordingToBudget():onNext");
                comicCount++;
            }
    
            @Override
            public void onError(Throwable e) {
                Timber.e("onFilterComicsForBudget:onError() %s", e);
            }
    
            @Override
            public void onComplete() {
                Timber.d("filterComicsAccordingToBudget():onComplete");
            }
        }
    });
    
    Observable.fromIterable(getMarvelComicsList())
        .map(new Function<MarvelComic, HashMap<String, Double>>() {
            HashMap<String, Double> myMap = new HashMap<String, Double>();
            double count = 0;
    
            @Override
            public HashMap<String, Double> apply(@NonNull MarvelComic marvelComic) throws Exception {
                myMap.put("price", Double.valueOf(marvelComic.getPrice()));
                myMap.put("pageCount", Double.valueOf(marvelComic.getPageCount()));
                myMap.put("comicsCount", count++);
                return myMap;
            }
        })
        .takeWhile(new Predicate<HashMap<String, Double>>() {
    
            double sum;
    
            @Override
            public boolean test(@NonNull HashMap<String, Double> map) throws Exception {
                Timber.e("sum is: %s", sum);
                return (sum += map.get("price")) < 5.00;
            }
        })
        .subscribe(new Observer<HashMap<String, Double>>() {
    
            @Override
            public void onSubscribe(Disposable d) {
            }
    
            @Override
            public void onNext(HashMap<String, Double> map) {
                Timber.e("value in onNext is: %s %s %s", map.get("pageCount"), map.get("price"), map.get("comicsCount"));
            }
    
            @Override
            public void onError(Throwable e) {
                Timber.e("onError()!!!   %s",e);
            }
    
            @Override
            public void onComplete() {
                Timber.e("onComplete()!!!");
            }
        });
    
    Observable.fromIterable(getMarvelComicList())
    .map(新函数(){
    HashMap myMap=新HashMap();
    重复计数=0;
    @凌驾
    公共HashMap apply(@NonNull)引发异常{
    myMap.put(“price”,Double.valueOf(marvelComic.getPrice());
    myMap.put(“pageCount”,Double.valueOf(marvelComic.getPageCount());
    myMap.put(“ComicCount”,count++);
    返回myMap;
    }
    })
    .takeWhile(新谓词(){
    双和;
    @凌驾
    公共布尔测试(@NonNull HashMap map)引发异常{
    木材.e(“总和为:%s”,总和);
    返回(总和+=映射获取(“价格”))<5.00;
    }
    })
    .订阅(新观察员){
    @凌驾
    认购的公共无效(一次性d){
    }
    @凌驾
    public void onNext(HashMap映射){
    Timber.e(“onNext中的值为:%s%s%s”、map.get(“pageCount”)、map.get(“价格”)、map.get(“ComicCount”);
    }
    @凌驾
    公共无效申报人(可丢弃的e){
    木材.e(“onError()!!!%s”,e);
    }
    @凌驾
    未完成的公共空间(){
    Timber.e(“onComplete()!!!”);
    }
    });
    

    我有点喜欢第一个实现,因为它比我习惯的更重要,对我来说似乎不那么笨重,但是考虑到我在RxJava方面的有限知识,我可能完全错了。

    我会避免为这种操作创建自定义的
    可观察的
    。您可以使用普通的RxJava操作符完成所有需要的操作

    在飞行中,我会这样做:

    private Observable<Double> getLimitObservable(final double budget) {
        return Observable.fromIterable(getMarvelComicsList())
              .scan(0D, (aDouble, marvelComic) -> aDouble + marvelComic.getPrice()) 
              .takeWhile(aDouble -> aDouble < budget)
              .skip(1);
    }
    
    现在,我将前面的可观察对象与新的可观察对象相结合(使用zip操作符),它将为每两个项目生成一个新项目(一个来自第一个可观察对象,一个来自第二个可观察对象),通过这种方式,您将获得与两个可观察对象发出的最小项目数相等的项目数。更多细节

    这将打印列表中第一批漫画的列表,直到您达到预算限制


    我打赌有更好的解决方案,但这只是一个例子。

    我会避免为此类操作创建自定义的
    可观察的
    。您可以使用普通的RxJava操作符完成所有需要的操作

    在飞行中,我会这样做:

    private Observable<Double> getLimitObservable(final double budget) {
        return Observable.fromIterable(getMarvelComicsList())
              .scan(0D, (aDouble, marvelComic) -> aDouble + marvelComic.getPrice()) 
              .takeWhile(aDouble -> aDouble < budget)
              .skip(1);
    }
    
    现在,我将前面的可观察对象与新的可观察对象相结合(使用zip操作符),它将为每两个项目生成一个新项目(一个来自第一个可观察对象,一个来自第二个可观察对象),通过这种方式,您将获得与两个可观察对象发出的最小项目数相等的项目数。更多细节

    这将打印列表中第一批漫画的列表,直到您达到预算限制


    我打赌有更好的解决方案,但这只是一个例子。

    为什么不使用我编写的第二个实现呢?用OPI编写的“第二个实现”中的描述是什么?我认为在谓词内部创建局部变量不是一个好主意(它似乎不起作用):您可以使用操作符来完成这项工作。此外,我不理解
    HashMap
    在这种上下文中的用法。我还要指出,在
    .create()
    内部使用
    getMarvelComicList()
    的可扩展性不强。例如,有一天您可能会决定将其作为
    Obs从服务器接收