1

I have started reading about RxJava / RxAndroid, but I can't find simple tutorial that covers typical thing, like getting network data and updating UI with the result.

Many tutorials cover scenario like running one or more background tasks, that take a parameter and return nothing.

Lets say I have a slow function that may return data or throw an Exception, like this:

private String getNetworkData(Integer parameter) throws Exception {
    Thread.sleep(1000);                // simulated delay
    switch (parameter) {
        case 0: return "Bill";
        case 1: return "Joe";
        case 2: return "Bob";
        case 3: return "Alex";
        case 4: return "Mary";
        default: throw new Exception("No such user");
    }
}

So far, I have written something like this: in my MainActivity I have a button with onClick set like this:

button.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {

        Observable<Integer> observable = Observable
                .just(0, 1, 3, 4, 8)                        // these are call parameters, right?
                .subscribeOn(Schedulers.io())               // this is where I do slow work, right?
                .observeOn(AndroidSchedulers.mainThread()); // this is where I get results, right?

        observable.subscribe(new Observer<Integer>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                Log.d(TAG,"onSubscribe on " + Thread.currentThread().getName());
            }

            @Override
            public void onNext(@NonNull Integer i) {

                // what to do with returned?
                // how do I catch errors?
                String returnedData = getNetworkData(i);
                Log.d(TAG,"onNext on " + Thread.currentThread().getName());
            }

            @Override
            public void onError(@NonNull Throwable e) {
                // how and where to throw errors that can be processed here?
                Log.d(TAG,"onSubscribe on " + Thread.currentThread().getName());
            }

            @Override
            public void onComplete() {
                Log.d(TAG,"onComplete on " + Thread.currentThread().getName());
            }
        });
    }
});

The question is: how can I update UI and receive returned data?

I have tried to understand something from this:

How to return value in rxJava

but it does not explain anything to me, I have no idea what type is youtubeApi (is it Observable or what?).

After some discussion in comments under another question I changed my button handler to this:

Callable callable = new Callable<String>() {
    @Override
    public String call() throws Exception {
        Log.d(TAG, "callable called on " + Thread.currentThread().getName());
        Thread.sleep(1000);                // simulated delay
        throw new Exception("Exception!");
        // return "Bill";
        // this is not what I want, because I can't get any parameter from here
    }
};

SingleObserver<String> observer = new SingleObserver<String>() {
    @Override
    public void onSubscribe(@NonNull Disposable d) {
        Log.d(TAG, "onSubscribe called on " + Thread.currentThread().getName());
    }

    @Override
    public void onSuccess(@NonNull String s) {
        Log.d(TAG, "onSuccess called on " + Thread.currentThread().getName());
    }

    @Override
    public void onError(@NonNull Throwable e) {
        Log.d(TAG, "onError called on " + Thread.currentThread().getName());
    }
};

Single.fromCallable(callable)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(observer);

But now I can't pass a parameter to my slow function.

Kamil
  • 13,363
  • 24
  • 88
  • 183
  • In your first code snippet, replace `just(0, 1, 3, 4, 8)` with `just(0, 1, 3, 4, 8).flatMap { someNumber -> getNetworkDataSingle(someNumber) }` (fixing things up for Java syntax, as I haven't written a Java lambda in years). `getNetworkDataSingle()` would return a `Single` using `Single.fromCallable()` to call your `getNetworkData()` function. I have no idea what the second code snippet has to do with the first one. – CommonsWare Sep 20 '22 at 17:34
  • First code is my try with passing parameter to background code. Second code is a try with getting result from background code. My problem is to combine both (call a function in the background and get result or error on main thread. – Kamil Sep 20 '22 at 17:38
  • @CommonsWare I don't get it. If it uses `Single.fromCallable()` - how I'm supposed to provide a parameter there? – Kamil Sep 20 '22 at 17:55

1 Answers1

0

OK. I got this.

So we need an observer, which will update our view.

Observer<String> observer = new Observer<String>() {
    @Override
    public void onSubscribe(@NonNull Disposable d) {
        Log.d(TAG, "onSubscribe called on thread " + Thread.currentThread().getName());
    }

    @Override
    public void onNext(@NonNull String s) {
        Log.d(TAG, "onNext called on thread " + Thread.currentThread().getName() + " returned data " + s);
    }

    @Override
    public void onError(@NonNull Throwable e) {
        Log.d(TAG, "onError called on thread " + Thread.currentThread().getName() + " with message " + e.getMessage());
    }

    @Override
    public void onComplete() {
        Log.d(TAG, "onComplete called on thread " + Thread.currentThread().getName());
    }
};

I need a function, that takes Integer as parameter (this will be my database Id) and returns String (this will be data returned from database).

Function<Integer, String> getNameByIdFunction = new Function<Integer, String>() {
    @Override
    public String apply(Integer integer) throws Throwable {
        Thread.sleep(1000);                // simulated delay
        switch (integer) {
            case 0:
                return "Bill";
            case 1:
                return "Joe";
            case 2:
                return "Bob";
            case 3:
                return "Alex";
            case 4:
                return "Mary";
            default:
                throw new Exception("No such user");
        }
    }
};

And finally we need to connect everything together with Observable.

Observable
        .just(1,3,5,0,4) // I want 5 function calls with diffrent parameters
        .map(getNameByIdFunction) // this is my function
        .subscribeOn(Schedulers.io()) // this is thread for a function
        .observeOn(AndroidSchedulers.mainThread()) // this is thread that will update my UI
        .subscribe(observer); // everything will start after we subscribe
Kamil
  • 13,363
  • 24
  • 88
  • 183