Handle null in RxJava2

亡梦爱人 提交于 2019-12-24 07:27:50

问题


There is a need where I want load data from local or remote. If local data fetched, remote data won't be fetched.

As local data can be empty (i.e. null), I have to handle null situation in RxJava2, so I do it with help of Optional util in java-8. Here is code.

String data;

Observable<Optional<String>> loadCacheData() {
    return Observable.create(emitter -> {
        emitter.onNext(Optional.ofNullable(null));
        emitter.onComplete();
    });
}

Observable<Optional<String>> loadRemoteData() {
    Observable<Optional<String>> remoteObservable = Observable.create((ObservableOnSubscribe<Optional<String>>) emitter -> {
        Thread.sleep(2000);
        emitter.onNext(Optional.of("FromRemote"));
        emitter.onComplete();
    }).subscribeOn(Schedulers.io());

    remoteObservable.doOnNext(s -> data = s.get());

    return remoteObservable;
}

void fetchData() {
    Observable.concat(loadCacheData(), loadRemoteData())
            .filter(s -> s.isPresent())
            .firstElement()
            .subscribe(s -> System.out.println(s.get()));
}

I want to know is there any other way to handle null in such situation.


回答1:


It seems like what you are trying to do is exactly what Maybe provides: a source that can either have or not have data.

Here's an example of how I see this working:

public class MaybeExample {

    private final Network network;

    private String cachedData;

    public MaybeExample(final MaybeNetwork network) {
        this.network = network;
    }

    // Just used for the test... you'll probably have something smarter
    public void setCachedData(final String data) {
        cachedData = data;
    }

    private Maybe<String> loadCacheData() {
        return cachedData != null ? Maybe.just(cachedData) : Maybe.empty();
    }

    private Single<String> loadRemoteData() {
        return network.getData();
    }

    public Single<String> fetchData() {
        return loadCacheData().switchIfEmpty(loadRemoteData());
    }
}

And this would be a test to see it in action:

public class MaybeExampleTest {

    @Mock
    private Network network;

    private MaybeExample maybeExample;

    @Before
    public void createExample() {
        MockitoAnnotations.initMocks(this);
        maybeExample = new MaybeExample(network);
    }

    @Test
    public void nullCachedDataReturnsNetworkData() {
        maybeExample.setCachedData(null);
        final String networkValue = "FromNetwork";
        when(network.getData()).thenReturn(Single.just(networkValue));

        final TestObserver<String> observer = maybeExample.fetchData().test();

        observer.assertValue(networkValue);
    }

    @Test
    public void cachedDataIsReturnedWithoutCallingNetwork() {
        final String cachedValue = "FromCache";
        maybeExample.setCachedData(cachedValue);
        when(network.getData()).thenReturn(Single.error(new UnsupportedOperationException()));

        final TestObserver<String> observer = maybeExample.fetchData().test();

        observer.assertValue(cachedValue);
        observer.assertNoErrors();
    }
}



回答2:


You can't send null to RxJava2 and you shouldn't do that, instead you can pass an empty list of your data.

switchIfEmpty() method can help you in both cases (network and local calls).




回答3:


I've seen in quite some projects the idea of returning static 'DEFAULT' object of given class. I don't feel much into this solution but it actually is other (and not so rare) way to handle null in RxJava.

It looks something like this:

class Anything(...) {
   companion object {
       val DEFAULT = Anything(...)
   }
}

Observable.fromCallable { getAnythingObject() }
            .onErrorReturn { Anything.DEFAULT }

And then checking:

    fun onReceived(anything: Anything) =
        when {
            anything === Anything.DEFAULT -> <TA DA!>
        }


来源:https://stackoverflow.com/questions/49196095/handle-null-in-rxjava2

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!