首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >什么时候应该使用可观察到的RxJava,以及何时在安卓上进行简单回调?

什么时候应该使用可观察到的RxJava,以及何时在安卓上进行简单回调?
EN

Stack Overflow用户
提问于 2014-02-19 19:25:04
回答 9查看 95.3K关注 0票数 268

我正在为我的应用程序建立关系网。所以我决定试试Square的改造。我看到他们支持简单的Callback

代码语言:javascript
复制
@GET("/user/{id}/photo")
void getUserPhoto(@Path("id") int id, Callback<Photo> cb);

和RxJava的Observable

代码语言:javascript
复制
@GET("/user/{id}/photo")
Observable<Photo> getUserPhoto(@Path("id") int id);

乍一看,两者看起来很相似,但是当它实现的时候,它变得很有趣.

虽然使用简单的回调实现看起来类似于以下内容:

代码语言:javascript
复制
api.getUserPhoto(photoId, new Callback<Photo>() {
    @Override
    public void onSuccess() {
    }
});

很简单也很简单。使用Observable,它很快就变得冗长而复杂。

代码语言:javascript
复制
public Observable<Photo> getUserPhoto(final int photoId) {
    return Observable.create(new Observable.OnSubscribeFunc<Photo>() {
        @Override
        public Subscription onSubscribe(Observer<? super Photo> observer) {
            try {
                observer.onNext(api.getUserPhoto(photoId));
                observer.onCompleted();
            } catch (Exception e) {
                observer.onError(e);
            }

            return Subscriptions.empty();
        }
    }).subscribeOn(Schedulers.threadPoolForIO());
}

不是这样的。你还得这样做:

代码语言:javascript
复制
Observable.from(photoIdArray)
        .mapMany(new Func1<String, Observable<Photo>>() {
            @Override
            public Observable<Photo> call(Integer s) {
                return getUserPhoto(s);
            }
        })
        .subscribeOn(Schedulers.threadPoolForIO())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<Photo>() {
            @Override
            public void call(Photo photo) {
                //save photo?
            }
        });

我是不是漏掉了什么?或者使用Observables是错误的情况吗?与简单的回调相比,何时/应该更喜欢Observable

更新

使用改进比上面的例子简单得多,@Niels在他的答案或杰克沃顿的示例项目U2020中都显示了这一点。但从本质上讲,问题仍然是一样的--什么时候应该以某种方式使用?

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2015-04-28 11:34:19

对于简单的网络内容,RxJava相对于回调的优势非常有限。简单的getUserPhoto示例:

RxJava:

代码语言:javascript
复制
api.getUserPhoto(photoId)
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Action1<Photo>() {
            @Override
            public void call(Photo photo) {
               // do some stuff with your photo 
            }
     });

回调:

代码语言:javascript
复制
api.getUserPhoto(photoId, new Callback<Photo>() {
    @Override
    public void onSuccess(Photo photo, Response response) {
    }
});

RxJava变体并不比回调变体好多少。现在,让我们忽略错误处理。让我们照张照片清单:

RxJava:

代码语言:javascript
复制
api.getUserPhotos(userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Func1<List<Photo>, Observable<Photo>>() {
    @Override
    public Observable<Photo> call(List<Photo> photos) {
         return Observable.from(photos);
    }
})
.filter(new Func1<Photo, Boolean>() {
    @Override
    public Boolean call(Photo photo) {
         return photo.isPNG();
    }
})
.subscribe(
    new Action1<Photo>() {
    @Override
        public void call(Photo photo) {
            list.add(photo)
        }
    });

回调:

代码语言:javascript
复制
api.getUserPhotos(userId, new Callback<List<Photo>>() {
    @Override
    public void onSuccess(List<Photo> photos, Response response) {
        List<Photo> filteredPhotos = new ArrayList<Photo>();
        for(Photo photo: photos) {
            if(photo.isPNG()) {
                filteredList.add(photo);
            }
        }
    }
});

现在,RxJava变体仍然不小,尽管有了Lambdas,它会更接近回调变量。此外,如果您能够访问JSON提要,那么当您只显示PNG时,检索所有照片可能会有些奇怪。只需调整馈送到它只显示PNG。

第一结论

当您加载一个简单的JSON时,它不会使您的代码库更小,而您准备以正确的格式加载它。

现在,让我们让事情变得更有趣一些。假设您不仅想检索userPhoto,而且您有一个Instagram-克隆,您希望检索2个JSON: 1. getUserDetails() 2. getUserPhotos()

您希望并行加载这两个JSON,当加载这两个JSON时,应该显示页面。回调变量将变得更加困难:您必须创建2个回调,将数据存储在活动中,如果加载了所有数据,则显示页面:

回调:

代码语言:javascript
复制
api.getUserDetails(userId, new Callback<UserDetails>() {
    @Override
    public void onSuccess(UserDetails details, Response response) {
        this.details = details;
        if(this.photos != null) {
            displayPage();
        }
    }
});

api.getUserPhotos(userId, new Callback<List<Photo>>() {
    @Override
    public void onSuccess(List<Photo> photos, Response response) {
        this.photos = photos;
        if(this.details != null) {
            displayPage();
        }
    }
});

RxJava:

代码语言:javascript
复制
private class Combined {
    UserDetails details;
    List<Photo> photos;
}


Observable.zip(api.getUserDetails(userId), api.getUserPhotos(userId), new Func2<UserDetails, List<Photo>, Combined>() {
            @Override
            public Combined call(UserDetails details, List<Photo> photos) {
                Combined r = new Combined();
                r.details = details;
                r.photos = photos;
                return r;
            }
        }).subscribe(new Action1<Combined>() {
            @Override
            public void call(Combined combined) {
            }
        });

我们有进展了!RxJava的代码现在和回调选项一样大。RxJava代码更健壮;如果我们需要加载第三个JSON (比如最新的视频),那么会发生什么呢?RxJava只需要很小的调整,而回调变量需要在多个地方进行调整(在每个回调中,我们需要检查是否检索了所有数据)。

另一个例子;我们希望创建一个自动完成字段,该字段使用Retrofit加载数据。我们不想每次EditText有TextChangedEvent时都打一个网络电话。在快速输入时,只有最后一个元素应该触发调用。在RxJava上,我们可以使用use操作符:

代码语言:javascript
复制
inputObservable.debounce(1, TimeUnit.SECONDS).subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                // use Retrofit to create autocompletedata
            }
        });

我不会创建回调变量,但是您会明白这是更多的工作。

结论:当数据作为流发送时,RxJava是非常好的。Retrofit可观测到的推送流上的所有元素同时。与回调相比,这本身并不特别有用。但是,当有多个元素被推到流上和不同的时间,并且您需要做与时间相关的事情时,RxJava使代码更易于维护。

票数 359
EN

Stack Overflow用户

发布于 2014-03-04 11:35:51

可以观察到的东西已经在Retrofit中完成了,所以代码可以是:

代码语言:javascript
复制
api.getUserPhoto(photoId)
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Action1<Photo>() {
         @Override
            public void call(Photo photo) {
                //save photo?
            }
     });
票数 68
EN

Stack Overflow用户

发布于 2014-03-07 09:34:26

在getUserPhoto()的情况下,RxJava的优势并不大。但是,让我们以另一个例子为例,当您将为用户获取所有照片时,但仅当图像为PNG时,并且您无法访问JSON来在服务器端进行过滤。

代码语言:javascript
复制
api.getUserPhotos(userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Func1<List<Photo>, Observable<Photo>>() {
    @Override
    public Observable<Photo> call(List<Photo> photos) {
         return Observable.from(photos);
    }
})
.filter(new Func1<Photo, Boolean>() {
    @Override
    public Boolean call(Photo photo) {
         return photo.isPNG();
    }
})
.subscribe(
    new Action1<Photo>() {
    @Override
        public void call(Photo photo) {
            // on main thread; callback for each photo, add them to a list or something.
            list.add(photo)
        }
    }, 
    new Action1<Throwable>() {
    @Override
        public void call(Throwable throwable) {
            // on main thread; something went wrong
            System.out.println("Error! " + throwable);
        }
    }, 
    new Action0() {
        @Override
        public void call() {
            // on main thread; all photo's loaded, time to show the list or something.
        }
    });

现在,JSON返回照片的列表,我们将把它们flatMap到各个项目。通过这样做,我们将能够使用过滤器方法来忽略不是PNG的照片。在此之后,我们将订阅,并在完成所有行时为每个单独的照片、一个errorHandler和一个回调提供一个回调。

TLDR Point在这里;回调只为成功和失败返回回调;可观察到的RxJava允许您执行映射、缩减、筛选等操作。

票数 35
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21890338

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档