|
15 | 15 | */
|
16 | 16 | package rx.subjects;
|
17 | 17 |
|
18 |
| -import java.util.Collection; |
19 |
| -import java.util.concurrent.atomic.AtomicReference; |
20 | 18 |
|
21 |
| -import rx.Notification; |
22 | 19 | import rx.Observer;
|
| 20 | +import rx.Subscriber; |
23 | 21 | import rx.functions.Action0;
|
24 | 22 | import rx.functions.Action1;
|
| 23 | +import rx.operators.NotificationLite; |
25 | 24 | import rx.subjects.SubjectSubscriptionManager.SubjectObserver;
|
| 25 | +import rx.subscriptions.Subscriptions; |
26 | 26 |
|
27 | 27 | /**
|
28 | 28 | * Subject that publishes the most recent and all subsequent events to each subscribed {@link Observer}.
|
|
65 | 65 | *
|
66 | 66 | * @param <T>
|
67 | 67 | */
|
| 68 | +@SuppressWarnings({ "unchecked", "rawtypes" }) |
68 | 69 | public final class BehaviorSubject<T> extends Subject<T, T> {
|
69 |
| - |
| 70 | + /** |
| 71 | + * Create a {@link BehaviorSubject} without a default value. |
| 72 | + * @param <T> the value type |
| 73 | + * @return the constructed {@link BehaviorSubject} |
| 74 | + */ |
| 75 | + public static <T> BehaviorSubject<T> create() { |
| 76 | + return create(null, false); |
| 77 | + } |
70 | 78 | /**
|
71 | 79 | * Creates a {@link BehaviorSubject} which publishes the last and all subsequent events to each {@link Observer} that subscribes to it.
|
72 | 80 | *
|
| 81 | + * @param <T> the value type |
73 | 82 | * @param defaultValue
|
74 | 83 | * the value which will be published to any {@link Observer} as long as the {@link BehaviorSubject} has not yet received any events
|
75 | 84 | * @return the constructed {@link BehaviorSubject}
|
76 | 85 | */
|
77 | 86 | public static <T> BehaviorSubject<T> create(T defaultValue) {
|
78 |
| - final SubjectSubscriptionManager<T> subscriptionManager = new SubjectSubscriptionManager<T>(); |
79 |
| - // set a default value so subscriptions will immediately receive this until a new notification is received |
80 |
| - final AtomicReference<Notification<T>> lastNotification = new AtomicReference<Notification<T>>(Notification.createOnNext(defaultValue)); |
81 |
| - |
82 |
| - OnSubscribe<T> onSubscribe = subscriptionManager.getOnSubscribeFunc( |
83 |
| - /** |
84 |
| - * This function executes at beginning of subscription. |
85 |
| - * |
86 |
| - * This will always run, even if Subject is in terminal state. |
87 |
| - */ |
88 |
| - new Action1<SubjectObserver<? super T>>() { |
89 |
| - |
90 |
| - @Override |
91 |
| - public void call(SubjectObserver<? super T> o) { |
92 |
| - /* |
93 |
| - * When we subscribe we always emit the latest value to the observer. |
94 |
| - * |
95 |
| - * Here we only emit if it's an onNext as terminal states are handled in the next function. |
96 |
| - */ |
97 |
| - Notification<T> n = lastNotification.get(); |
98 |
| - if (n.isOnNext()) { |
99 |
| - n.accept(o); |
100 |
| - } |
101 |
| - } |
102 |
| - }, |
103 |
| - /** |
104 |
| - * This function executes if the Subject is terminated before subscription occurs. |
105 |
| - */ |
106 |
| - new Action1<SubjectObserver<? super T>>() { |
107 |
| - |
108 |
| - @Override |
109 |
| - public void call(SubjectObserver<? super T> o) { |
110 |
| - /* |
111 |
| - * If we are already terminated, or termination happens while trying to subscribe |
112 |
| - * this will be invoked and we emit whatever the last terminal value was. |
113 |
| - */ |
114 |
| - lastNotification.get().accept(o); |
115 |
| - } |
116 |
| - }, null); |
| 87 | + return create(defaultValue, true); |
| 88 | + } |
| 89 | + private static <T> BehaviorSubject<T> create(T defaultValue, boolean hasDefault) { |
| 90 | + final SubjectSubscriptionManager<T> state = new SubjectSubscriptionManager<T>(); |
| 91 | + if (hasDefault) { |
| 92 | + state.set(NotificationLite.instance().next(defaultValue)); |
| 93 | + } |
| 94 | + state.onAdded = new Action1<SubjectObserver<T>>() { |
117 | 95 |
|
118 |
| - return new BehaviorSubject<T>(onSubscribe, subscriptionManager, lastNotification); |
| 96 | + @Override |
| 97 | + public void call(SubjectObserver<T> o) { |
| 98 | + o.emitFirst(state.get()); |
| 99 | + } |
| 100 | + |
| 101 | + }; |
| 102 | + state.onTerminated = state.onAdded; |
| 103 | + return new BehaviorSubject<T>(state, state); |
119 | 104 | }
|
120 | 105 |
|
121 |
| - private final SubjectSubscriptionManager<T> subscriptionManager; |
122 |
| - final AtomicReference<Notification<T>> lastNotification; |
| 106 | + private final SubjectSubscriptionManager<T> state; |
| 107 | + private final NotificationLite<T> nl = NotificationLite.instance(); |
123 | 108 |
|
124 |
| - protected BehaviorSubject(OnSubscribe<T> onSubscribe, SubjectSubscriptionManager<T> subscriptionManager, AtomicReference<Notification<T>> lastNotification) { |
| 109 | + protected BehaviorSubject(OnSubscribe<T> onSubscribe, SubjectSubscriptionManager<T> state) { |
125 | 110 | super(onSubscribe);
|
126 |
| - this.subscriptionManager = subscriptionManager; |
127 |
| - this.lastNotification = lastNotification; |
| 111 | + this.state = state; |
128 | 112 | }
|
129 | 113 |
|
130 | 114 | @Override
|
131 | 115 | public void onCompleted() {
|
132 |
| - Collection<SubjectObserver<? super T>> observers = subscriptionManager.terminate(new Action0() { |
133 |
| - |
134 |
| - @Override |
135 |
| - public void call() { |
136 |
| - lastNotification.set(Notification.<T> createOnCompleted()); |
137 |
| - } |
138 |
| - }); |
139 |
| - if (observers != null) { |
140 |
| - for (Observer<? super T> o : observers) { |
141 |
| - o.onCompleted(); |
| 116 | + Object last = state.get(); |
| 117 | + if (last == null || state.active) { |
| 118 | + Object n = nl.completed(); |
| 119 | + for (SubjectObserver<T> bo : state.terminate(n)) { |
| 120 | + bo.emitNext(n); |
142 | 121 | }
|
143 | 122 | }
|
144 | 123 | }
|
145 | 124 |
|
146 | 125 | @Override
|
147 |
| - public void onError(final Throwable e) { |
148 |
| - Collection<SubjectObserver<? super T>> observers = subscriptionManager.terminate(new Action0() { |
149 |
| - |
150 |
| - @Override |
151 |
| - public void call() { |
152 |
| - lastNotification.set(Notification.<T> createOnError(e)); |
153 |
| - } |
154 |
| - }); |
155 |
| - if (observers != null) { |
156 |
| - for (Observer<? super T> o : observers) { |
157 |
| - o.onError(e); |
| 126 | + public void onError(Throwable e) { |
| 127 | + Object last = state.get(); |
| 128 | + if (last == null || state.active) { |
| 129 | + Object n = nl.error(e); |
| 130 | + for (SubjectObserver<T> bo : state.terminate(n)) { |
| 131 | + bo.emitNext(n); |
158 | 132 | }
|
159 | 133 | }
|
160 | 134 | }
|
161 | 135 |
|
162 | 136 | @Override
|
163 | 137 | public void onNext(T v) {
|
164 |
| - // do not overwrite a terminal notification |
165 |
| - // so new subscribers can get them |
166 |
| - if (lastNotification.get().isOnNext()) { |
167 |
| - lastNotification.set(Notification.createOnNext(v)); |
168 |
| - for (Observer<? super T> o : subscriptionManager.rawSnapshot()) { |
169 |
| - o.onNext(v); |
| 138 | + Object last = state.get(); |
| 139 | + if (last == null || state.active) { |
| 140 | + Object n = nl.next(v); |
| 141 | + for (SubjectObserver<T> bo : state.next(n)) { |
| 142 | + bo.emitNext(n); |
170 | 143 | }
|
171 | 144 | }
|
172 | 145 | }
|
173 |
| - |
| 146 | + |
| 147 | + /* test support */ int subscriberCount() { |
| 148 | + return state.observers().length; |
| 149 | + } |
174 | 150 | }
|
0 commit comments