Querying single database row using rxjava2

2019-07-26 07:38发布

I am using rxjava2 for the first time on an Android project, and am doing SQL queries on a background thread.

However I am having trouble figuring out the best way to do a simple SQL query, and being able to handle the case where the record may or may not exist. Here is the code I am using:

public Observable<Record> createRecordObservable(int id) {
    Callable<Record> callback = new Callable<Record>() {
        @Override
        public Record call() throws Exception {
            // do the actual sql stuff, e.g.
            // select * from Record where id = ?
            return record;
        }
    };
    return Observable.fromCallable(callback).subscribeOn(Schedulers.computation());
}

This works well when there is a record present. But in the case of a non-existent record matching the id, it treats it like an error. Apparently this is because rxjava2 doesn't allow the Callable to return a null.

Obviously I don't really want this. An error should be only if the database failed or something, whereas a empty result is perfectly valid. I read somewhere that one possible solution is wrapping Record in a Java 8 Optional, but my project is not Java 8, and anyway that solution seems a bit ugly.

This is surely such a common, everyday task that I'm sure there must be a simple and easy solution, but I couldn't find one so far. What is the recommended pattern to use here?

2条回答
三岁会撩人
2楼-- · 2019-07-26 07:44

Thanks to @yosriz, I have it working with Maybe. Since I can't put code in comments, I'll post a complete answer here:

Instead of Observable, use Maybe like this:

public Maybe<Record> lookupRecord(int id) {
    Callable<Record> callback = new Callable<Record>() {
        @Override
        public Record call() throws Exception {
            // do the actual sql stuff, e.g.
            // select * from Record where id = ?
            return record;
        }
    };
    return Maybe.fromCallable(callback).subscribeOn(Schedulers.computation());
}

The good thing is the returned record is allowed to be null. To detect which situation occurred in the subscriber, the code is like this:

lookupRecord(id)
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Consumer<Record>() {
            @Override
            public void accept(Record r) {
                // record was loaded OK

            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) {
                // there was an error

            }
        }, new Action() {
            @Override
            public void run() {
                // there was an empty result
            }
        });
查看更多
孤傲高冷的网名
3楼-- · 2019-07-26 07:53

Your use case seems appropriate for the RxJava2 new Observable type Maybe, which emit 1 or 0 items.
Maybe.fromCallable will treat returned null as no items emitted.

You can see this discussion regarding nulls with RxJava2, I guess that there is no many choices but using Optional alike in other cases where you need nulls/empty values.

查看更多
登录 后发表回答