Как вернуть значение в RxJava

#android #rx-java

#Android #rx-java

Вопрос:

Я новичок в RxJava, и у меня от этого кружится голова. По сути, я извлекаю данные из api youtube с помощью retrofit, который возвращает Observable, а с помощью youtubeDataMapper я отображаю их в объект Youtube Pojo, который содержит строку VideoID. Итак, мой вопрос в том, как заставить этот метод возвращать эту строку вместо завершаемой?

Это мой метод:

 @Override
  public Completable downloadVideoUrl(String query) {

    addSubscription(youtubeApi.getYoutubeId(query, Constants.youtubeApi)
                              .map(youtubeDataMapper::map)
                              .subscribeOn(subscribeScheduler)
                              .observeOn(observeScheduler)
                              .subscribe());
    return Completable.complete();
}
  

Ответ №1:

У вас есть два варианта:

  1. Сделайте свой downloadVideoUrl возврат Observable вместо Completable :

    Предпочтительный способ:

     @Override
    public Completable downloadVideoUrl(String query) {
        return youtubeApi.getYoutubeId(query, Constants.youtubeApi)
                .map(youtubeDataMapper::map)
                .subscribeOn(subscribeScheduler)
                .observeOn(observeScheduler);
    }
      

    Обратите внимание на отсутствие subscribe оператора здесь.

    Затем везде, где вы хотите получить VideoID:

     downloadVideoUrl(query)
        .subscribe(new Subscriber<String>() {
                    @Override
                    public void onCompleted() {
    
                    }
    
                    @Override
                    public void onError(Throwable e) {
    
                    }
    
                    @Override
                    public void onNext(String videoId) {
                        // do whatever you want with videoId
                    }
                });
      
  2. Используйте toBlocking().first()

    Это не предпочтительно, поскольку вы блокируете current Thread до Observable завершения

     @Override
    public String downloadVideoUrl(String query) {
        return youtubeApi.getYoutubeId(query, Constants.youtubeApi)
                .map(youtubeDataMapper::map)
                .subscribeOn(subscribeScheduler)
                .observeOn(observeScheduler)
                .toBlocking().first();
    }
      

Ответ №2:

Прежде всего, лучше сделать Retrofit return Single вместо Observable, потому что вы ожидаете один ответ сервера (а не последовательность ответов).

Во-вторых, Completable.complete() — это заводской метод для Completable, который вообще ничего не делает. Так что вам это здесь не нужно.

Что касается строкового VideoID, это зависит от того, что вы планируете с ним делать. Кроме того, я понятия не имею, что делает ваш .addSubscription().

Я бы предложил сделать что-то вроде следующего:

 
class YourClass {

    private final CompositeSubscription compositeSubscription = new CompositeSubscription();
    // you must call compositeSubscription.clear() either in class .finalize() or on some UI lifecycle event

    void yourMethod() {
        final Single videoID = youtubeApi.getYoutubeId(query, Constants.youtubeApi)
                .map(youtubeDataMapper::map)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
        final Subscription subscription = videoID.subscribe(new SingleSubscriber() {                    
                    @Overridepublic void onSuccess(String value) {
                        // TODO: do whatever with the value
                    }
                    @Override
                    public void onError(Throwable error) {                         
                        // TODO: log and/or display error
                    }
                });
       compositeSubscription.add(subscription);
    }
}