com.jakewharton.rxrelay2.PublishRelay Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rxrelay Show documentation
Show all versions of rxrelay Show documentation
Objects that are both an Observable and a Consumer.
/**
* Copyright (c) 2016-present, RxJava Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
* the License for the specific language governing permissions and limitations under the License.
*/
package com.jakewharton.rxrelay2;
import io.reactivex.Observer;
import io.reactivex.annotations.CheckReturnValue;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.subjects.PublishSubject;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
/**
* Relay that, once an {@link Observer} has subscribed, emits all subsequently observed items to the
* subscriber.
*
*
*
* Example usage:
*
*
{@code
PublishRelay
*/
public final class PublishRelay extends Relay {
/** An empty subscribers array to avoid allocating it all the time. */
@SuppressWarnings("rawtypes")
static final PublishDisposable[] EMPTY = new PublishDisposable[0];
/** The array of currently subscribed subscribers. */
final AtomicReference[]> subscribers;
/**
* Constructs a PublishRelay.
*/
@CheckReturnValue
@NonNull
public static PublishRelay create() {
return new PublishRelay();
}
/**
* Constructs a PublishRelay.
*/
@SuppressWarnings("unchecked")
PublishRelay() {
subscribers = new AtomicReference[]>(EMPTY);
}
@Override
protected void subscribeActual(Observer super T> t) {
PublishDisposable ps = new PublishDisposable(t, this);
t.onSubscribe(ps);
add(ps);
// if cancellation happened while a successful add, the remove() didn't work
// so we need to do it again
if (ps.isDisposed()) {
remove(ps);
}
}
/**
* Adds the given subscriber to the subscribers array atomically.
* @param ps the subscriber to add
*/
void add(PublishDisposable ps) {
for (;;) {
PublishDisposable[] a = subscribers.get();
int n = a.length;
@SuppressWarnings("unchecked")
PublishDisposable[] b = new PublishDisposable[n + 1];
System.arraycopy(a, 0, b, 0, n);
b[n] = ps;
if (subscribers.compareAndSet(a, b)) {
return;
}
}
}
/**
* Atomically removes the given subscriber if it is subscribed to the subject.
* @param ps the subject to remove
*/
@SuppressWarnings("unchecked")
void remove(PublishDisposable ps) {
for (;;) {
PublishDisposable[] a = subscribers.get();
if (a == EMPTY) {
return;
}
int n = a.length;
int j = -1;
for (int i = 0; i < n; i++) {
if (a[i] == ps) {
j = i;
break;
}
}
if (j < 0) {
return;
}
PublishDisposable[] b;
if (n == 1) {
b = EMPTY;
} else {
b = new PublishDisposable[n - 1];
System.arraycopy(a, 0, b, 0, j);
System.arraycopy(a, j + 1, b, j, n - j - 1);
}
if (subscribers.compareAndSet(a, b)) {
return;
}
}
}
@Override
public void accept(T value) {
if (value == null) throw new NullPointerException("value == null");
for (PublishDisposable s : subscribers.get()) {
s.onNext(value);
}
}
@Override
public boolean hasObservers() {
return subscribers.get().length != 0;
}
/**
* Wraps the actual subscriber, tracks its requests and makes cancellation
* to remove itself from the current subscribers array.
*
* @param the value type
*/
static final class PublishDisposable extends AtomicBoolean implements Disposable {
private static final long serialVersionUID = 3562861878281475070L;
/** The actual subscriber. */
final Observer super T> downstream;
/** The subject state. */
final PublishRelay parent;
/**
* Constructs a PublishSubscriber, wraps the actual subscriber and the state.
* @param actual the actual subscriber
* @param parent the parent PublishProcessor
*/
PublishDisposable(Observer super T> actual, PublishRelay parent) {
this.downstream = actual;
this.parent = parent;
}
public void onNext(T t) {
if (!get()) {
downstream.onNext(t);
}
}
@Override
public void dispose() {
if (compareAndSet(false, true)) {
parent.remove(this);
}
}
@Override
public boolean isDisposed() {
return get();
}
}
}