DEV Community

Cover image for Matt's Tidbits #41 - Converting a BehaviorRelay into a PublishRelay
Matthew Groves
Matthew Groves

Posted on • Originally published at Medium

2 1

Matt's Tidbits #41 - Converting a BehaviorRelay into a PublishRelay

Last week I explained the way errors don’t propagate outside of a doOnSubscribe() block. This time, I wanted to share an exciting discovery — how to convert a BehaviorRelay to a PublishRelay (and why you would want to).

On the project I’ve been working on recently, I was presented with an interesting challenge — I have a BehaviorRelay and need it to behave like a PublishRelay.

What’s the difference you ask? They’re both a type of RxJava Observable that does not allow for errors to be emitted. However, there is one fundamental difference — a BehaviorRelay will emit the most recent item when someone subscribes to it, while a PublishRelay will not.

Given that RxJava has nearly as many operators as emacs, you’d think there would be a built-in easy way to convert from a BehaviorRelay to a PublishRelay. Unfortunately, this is not the case. But, we can do a pretty good job of building one on our own!

Here’s what I came up with:

fun <T> convertBehaviorRelayToPublishRelay(behaviorRelay: BehaviorRelay<T>): Observable<T> {
return Observable.defer {
// If the BehaviorRelay has a value, skip it, as we want to wait for the *next* one
// We can't guarantee that the "next" value is actually emitted after we're completely finished subscribing,
// but at least it won't be _too_ stale.
if (behaviorRelay.hasValue()) {
behaviorRelay.skip(1)
} else {
behaviorRelay
}
}
}

The most obviously important part is the hasValue() check and corresponding skip(1) statement. This allows us to check if the BehaviorRelay has a value that it would emit upon subscription.

However, that’s not all of it — the Observable.defer() is also very important — this guarantees that we’re not checking if the BehaviorRelay has a value until the client subscribes to the Observable we’re returning. This means we reduce the window of time during which our call to hasValue() might change.

Unfortunately, this does not completely eliminate the possibility of things getting messed up — it’s possible, especially in a multi-threaded environment, that when we call behaviorRelay.hasValue() it returns false, but by the time we get ready to return the behaviorRelay itself a value will have been emitted, which we may have been intending to skip.

I’m not crazy about there still being a chance for things to go wrong, but this is the best I could come up with. Do you have an idea for how to improve this further? If so, please let me know in the comments! And, please follow me on Medium if you’re interested in being notified of future tidbits.

Interested in joining the awesome team here at Intrepid? We’re hiring!

This tidbit was discovered on October 24, 2019.

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay