19
19
import java .util .Iterator ;
20
20
import java .util .LinkedList ;
21
21
import java .util .List ;
22
+
22
23
import rx .Observable ;
23
24
import rx .Observable .Operator ;
25
+ import rx .Subscription ;
26
+ import rx .functions .Action0 ;
27
+ import rx .subscriptions .Subscriptions ;
24
28
import rx .Observer ;
25
29
import rx .Subscriber ;
26
30
@@ -56,11 +60,29 @@ public Subscriber<? super T> call(Subscriber<? super Observable<T>> child) {
56
60
final class ExactSubscriber extends Subscriber <T > {
57
61
final Subscriber <? super Observable <T >> child ;
58
62
int count ;
59
- Observer <T > consumer ;
60
- Observable < T > producer ;
63
+ BufferUntilSubscriber <T > window ;
64
+ Subscription parentSubscription = this ;
61
65
public ExactSubscriber (Subscriber <? super Observable <T >> child ) {
62
- super (child );
66
+ /**
67
+ * See https://github.com/ReactiveX/RxJava/issues/1546
68
+ * We cannot compose through a Subscription because unsubscribing
69
+ * applies to the outer, not the inner.
70
+ */
63
71
this .child = child ;
72
+ /*
73
+ * Add unsubscribe hook to child to get unsubscribe on outer (unsubscribing on next window, not on the inner window itself)
74
+ */
75
+ child .add (Subscriptions .create (new Action0 () {
76
+
77
+ @ Override
78
+ public void call () {
79
+ // if no window we unsubscribe up otherwise wait until window ends
80
+ if (window == null ) {
81
+ parentSubscription .unsubscribe ();
82
+ }
83
+ }
84
+
85
+ }));
64
86
}
65
87
66
88
@ Override
@@ -71,45 +93,66 @@ public void onStart() {
71
93
72
94
@ Override
73
95
public void onNext (T t ) {
74
- if (count ++ % size == 0 ) {
75
- if (consumer != null ) {
76
- consumer .onCompleted ();
96
+ if (window == null ) {
97
+ window = BufferUntilSubscriber .create ();
98
+ child .onNext (window );
99
+ }
100
+ window .onNext (t );
101
+ if (++count % size == 0 ) {
102
+ window .onCompleted ();
103
+ window = null ;
104
+ if (child .isUnsubscribed ()) {
105
+ parentSubscription .unsubscribe ();
106
+ return ;
77
107
}
78
- createNewWindow ();
79
- child .onNext (producer );
80
108
}
81
- consumer .onNext (t );
82
109
}
83
110
84
111
@ Override
85
112
public void onError (Throwable e ) {
86
- if (consumer != null ) {
87
- consumer .onError (e );
113
+ if (window != null ) {
114
+ window .onError (e );
88
115
}
89
116
child .onError (e );
90
117
}
91
118
92
119
@ Override
93
120
public void onCompleted () {
94
- if (consumer != null ) {
95
- consumer .onCompleted ();
121
+ if (window != null ) {
122
+ window .onCompleted ();
96
123
}
97
124
child .onCompleted ();
98
125
}
99
- void createNewWindow () {
100
- final BufferUntilSubscriber <T > bus = BufferUntilSubscriber .create ();
101
- consumer = bus ;
102
- producer = bus ;
103
- }
104
126
}
127
+
105
128
/** Subscriber with inexact, possibly overlapping or skipping windows. */
106
129
final class InexactSubscriber extends Subscriber <T > {
107
130
final Subscriber <? super Observable <T >> child ;
108
131
int count ;
109
- final List <CountedSubject <T >> chunks ;
132
+ final List <CountedSubject <T >> chunks = new LinkedList <CountedSubject <T >>();
133
+ Subscription parentSubscription = this ;
134
+
110
135
public InexactSubscriber (Subscriber <? super Observable <T >> child ) {
136
+ /**
137
+ * See https://github.com/ReactiveX/RxJava/issues/1546
138
+ * We cannot compose through a Subscription because unsubscribing
139
+ * applies to the outer, not the inner.
140
+ */
111
141
this .child = child ;
112
- this .chunks = new LinkedList <CountedSubject <T >>();
142
+ /*
143
+ * Add unsubscribe hook to child to get unsubscribe on outer (unsubscribing on next window, not on the inner window itself)
144
+ */
145
+ child .add (Subscriptions .create (new Action0 () {
146
+
147
+ @ Override
148
+ public void call () {
149
+ // if no window we unsubscribe up otherwise wait until window ends
150
+ if (chunks == null || chunks .size () == 0 ) {
151
+ parentSubscription .unsubscribe ();
152
+ }
153
+ }
154
+
155
+ }));
113
156
}
114
157
115
158
@ Override
@@ -121,10 +164,13 @@ public void onStart() {
121
164
@ Override
122
165
public void onNext (T t ) {
123
166
if (count ++ % skip == 0 ) {
124
- CountedSubject <T > cs = createCountedSubject ();
125
- chunks .add (cs );
126
- child .onNext (cs .producer );
167
+ if (!child .isUnsubscribed ()) {
168
+ CountedSubject <T > cs = createCountedSubject ();
169
+ chunks .add (cs );
170
+ child .onNext (cs .producer );
171
+ }
127
172
}
173
+
128
174
Iterator <CountedSubject <T >> it = chunks .iterator ();
129
175
while (it .hasNext ()) {
130
176
CountedSubject <T > cs = it .next ();
@@ -134,6 +180,10 @@ public void onNext(T t) {
134
180
cs .consumer .onCompleted ();
135
181
}
136
182
}
183
+ if (chunks .size () == 0 && child .isUnsubscribed ()) {
184
+ parentSubscription .unsubscribe ();
185
+ return ;
186
+ }
137
187
}
138
188
139
189
@ Override
@@ -155,6 +205,7 @@ public void onCompleted() {
155
205
}
156
206
child .onCompleted ();
157
207
}
208
+
158
209
CountedSubject <T > createCountedSubject () {
159
210
final BufferUntilSubscriber <T > bus = BufferUntilSubscriber .create ();
160
211
return new CountedSubject <T >(bus , bus );
0 commit comments