当前位置: 首页 > 知识库问答 >
问题:

在Android上什么时候应该使用RxJava Observable和什么时候简单回调?

霍建章
2023-03-14
@GET("/user/{id}/photo")
void getUserPhoto(@Path("id") int id, Callback<Photo> cb);
@GET("/user/{id}/photo")
Observable<Photo> getUserPhoto(@Path("id") int id);

而使用简单的回调实现则类似于如下所示:

api.getUserPhoto(photoId, new Callback<Photo>() {
    @Override
    public void onSuccess() {
    }
});

这是非常简单和直接的。使用observable,它很快就变得冗长和复杂。

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());
}

但事实并非如此。你还是要做这样的事情:

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在他的答案中或在Jake Wharton的示例项目U2020中所示,使用改型比上面的示例简单得多。但本质上,问题是一样的--什么时候该用这样或那样的方法?

共有1个答案

孙财
2023-03-14

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

RXJava:

api.getUserPhoto(photoId)
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Action1<Photo>() {
            @Override
            public void call(Photo photo) {
               // do some stuff with your photo 
            }
     });

回调:

api.getUserPhoto(photoId, new Callback<Photo>() {
    @Override
    public void onSuccess(Photo photo, Response response) {
    }
});
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)
        }
    });
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);
            }
        }
    }
});

第一个结论

当您加载一个简单的JSON时,它不会使您的代码库变小,因为您准备了正确的格式。

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

您希望并行加载这两个JSON,当这两个JSONs都加载时,应该会显示页面。回调变体会变得更难一点:你要创建2个回调,将数据存储在活动中,如果加载了所有数据,就显示页面:

回调:

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:

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只需要一个微小的调整,而回调变量需要在多个地方进行调整(在每次回调时,我们需要检查是否检索到了所有数据)。

inputObservable.debounce(1, TimeUnit.SECONDS).subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                // use Retrofit to create autocompletedata
            }
        });

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

结论:当数据以流形式发送时,RxJava表现得特别好。可观察的改型同时将所有元素推到流上。与回调相比,这本身并不是特别有用。但是,当流上有多个元素和不同的时间被推送,并且您需要做与时间相关的事情时,RxJava使代码的可维护性大大提高。

 类似资料:
  • 问题内容: 我知道他们两个都禁用了Nagle的算法。 我什么时候应该/不应该使用它们中的每一个? 问题答案: 首先,不是所有人都禁用Nagle的算法。 Nagle的算法用于减少有线中更多的小型网络数据包。该算法是:如果数据小于限制(通常是MSS),请等待直到收到先前发送的数据包的ACK,同时累积用户的数据。然后发送累积的数据。 这将对telnet等应用程序有所帮​​助。但是,在发送流数据时,等待A

  • 问题内容: 在该类中,有两个字符串,和。 有什么不同?我什么时候应该使用另一个? 问题答案: 如果你的意思是和则: 用于在文件路径列表中分隔各个文件路径。考虑在上的环境变量。您使用a分隔文件路径,因此在上将是;。 是或用于拆分到特定文件的路径。例如在上,或

  • 问题内容: 在集成我以前从未使用过的Django应用程序时,我发现了用于定义类中函数的两种不同方式。作者似乎非常有意地使用了它们。第一个是我自己经常使用的: 另一个是我不使用的,主要是因为我不知道何时使用它,以及什么用途: 在Python文档中,装饰器的解释如下: 类方法将类作为隐式第一个参数接收,就像实例方法接收实例一样。 所以我想指的是自己(而不是实例)。我不完全理解为什么会这样,因为我总是可

  • 问题内容: 奇怪的是: 似乎或多或少被定义为。通过这种方式很容易产生错误: 一些fname意外地以else块结尾。修复很简单,我们应该改用它,但是从表面上看,这似乎是一种不错的pythonic方式,并且比“正确”的方式更具可读性。 由于字符串是不可变的,所以为什么字符串错误是什么技术细节?什么时候进行身份检查更好,什么时候进行平等检查更好? 问题答案: 据我所知,检查对象身份是否相等。由于没有强制

  • 问题内容: 我看过各种文章,但我仍然不知道为什么不应该使用它。请让我知道您的想法。 问题答案: 我发现有必要在错误的设计中使用instanceof提示。可以肯定的是,将会出现一个大型,复杂的开关风格的构造。在我看到的其他大多数情况下,我们应该使用多态而不是instanceof。请参阅策略模式。(相关的使用示例) 我唯一需要使用的是实现时。

  • 问题内容: 我在阅读《 Swift编程语言》指南 时遇到了一个叫做的函数,但我仍然想知道为什么以及何时需要实现它,因为我们实际上不需要管理内存。 问题答案: 不需要实现该方法,但是如果需要在取消分配对象之前进行一些操作或清理,则可以使用它。 在苹果的文档包括例如: 因此,无论何时将玩家从游戏中移除,其硬币都会退还至银行。