Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxAndroid: Observable.first() returns List of null objects

Following this tutorial I've created two sources for fetching data. I expect that if there is no data locally I'll send network request. But all the time get list of null objects from local source (which is first in Observable.concat).

For local source using SQLite with SQLBrite wrapper and Retrofit for remote source:

@Override
public Observable<Item> get(String id) {
    //creating sql query

    return databaseHelper.createQuery(ItemEntry.TABLE_NAME, sqlQuery, id)
        .mapToOneOrDefault(mapperFunction, null);
}

There is method in repository for concating observables:

@Override
public Observable<Item> get(String id) {
    Observable<Item> local = localDataSource
        .get(id)
        .doOnNext(new Action1<Item>() {
            @Override
            public void call(final Item item) {
                // put item to cache
            }
        });
    Observable<Item> remote = remoteDataSource
        .get(id)
        .doOnNext(new Action1<Item>() {
            @Override
            public void call(final Item item) {
                // save item to database and put to cache
            }
        });
    return Observable.concat(local, remote).first();
}

For getting it with list of ids I'm using next method:

@Override
public Observable<List<Item>> getList(final List<String> ids) {
    return Observable
        .from(ids)
        .flatMap(new Func1<String, Observable<Item>>() {
            @Override
            public Observable<Item> call(String id) {
                return get(id);
            }
        }).toList();
}

And subscription in fragment:

Subscription subscription = repository
    .getList(ids)
    .flatMap(new Func1<List<Item>, Observable<Item>>() {
        @Override
        public Observable<Item> call(List<Item> result) {
            return Observable.from(result);
        }
    })
    .toList()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<List<Item>>() {
        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onNext(List<Item> result) {
            // there get list of null objects
        }
}); 

So, main goal is first check local storage and if there is no item - make request to server. But now if item isn't exist I get null instead of send request.

Could someone help me understand why?

like image 895
Alexander Molkov Avatar asked May 21 '26 04:05

Alexander Molkov


1 Answers

Calling first() after concat will of course return the first item, regardless if it's valid. Yout first() function should validate the value and only submit a 'valid' first item.

Something like:

public void test() {
    Integer[] ids = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    Observable.from(ids)
            .flatMap(new Func1<Integer, Observable<String>>() {
                @Override
                public Observable<String> call(Integer id) {
                    return get(id);
                }
            })
            .toList()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber<List<String>>() {
                @Override
                public void onCompleted() {

                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onNext(List<String> strings) {

                }
            });
}

public Observable<String> get(int id) {
    return Observable.concat(getLocal(id), getRemote(id))
            .first(new Func1<String, Boolean>() {
                @Override
                public Boolean call(String s) {
                    return s != null;
                }
            });
}

public Observable<String> getLocal(int id) {
    return Observable.just(id < 5 ? "fromLocal id:"+id : null);
}

public Observable<String> getRemote(int id) {
    return Observable.just(id >= 5 ? "fromRemote id:"+id : null);
}

Will bring u the result:

fromLocal id:1
fromLocal id:2
fromLocal id:3
fromLocal id:4
fromRemote id:5
fromRemote id:6
fromRemote id:7
fromRemote id:8
fromRemote id:9
fromRemote id:10
like image 185
Andre Classen Avatar answered May 22 '26 23:05

Andre Classen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!