12
votes

I'm new into rxJava and it's making my head spin. Basically I'm pulling data from youtube api with retrofit which gives back Observable and with youtubeDataMapper I'm mappng it into Youtube Pojo object which contains String videoID. So my question is, how to make this method return that string instead of Completable?

This is my method:

@Override
  public Completable downloadVideoUrl(String query) {

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

2 Answers

10
votes

You have two choices:

  1. Make your downloadVideoUrl return Observable instead of Completable:

    Preferred way:

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

    Notice lack of subscribe operator here.

    Then wherever you want to get 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. Use toBlocking().first()

    This is not preffered as you block current Thread until Observable finishes

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

First of all, it is better to make Retrofit return Single instead of Observable because you are expecting a single server response (and not a sequence of responses).

Secondly, Completable.complete() is a factory method for a Completable that does nothing at all. So you don’t need it here.

Regarding String videoID, it depends on what you are planning to do with it. Also, I have no idea what your .addSubscription() is doing.

I would suggest doing something like the following:


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() {                    
                    @Override
                    public 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);
    }
}