Skip to content

Commit ddbd8d7

Browse files
committed
Merge pull request ReactiveX#20 from naghtarr/naghtarr/itemclicks
Add OperatorAdapterViewOnItemClick to observe OnItemClick events in AdapterViews. Resolve ReactiveX#19.
2 parents 2bb5640 + db454db commit ddbd8d7

File tree

6 files changed

+559
-15
lines changed

6 files changed

+559
-15
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package rx.android.events;
2+
3+
import android.view.View;
4+
import android.widget.Adapter;
5+
import android.widget.AdapterView;
6+
7+
public class OnItemClickEvent {
8+
public final AdapterView<?> parent;
9+
public final View view;
10+
public final int position;
11+
public final long id;
12+
13+
public OnItemClickEvent(AdapterView<?> parent, View view, int position, long id) {
14+
this.parent = parent;
15+
this.view = view;
16+
this.position = position;
17+
this.id = id;
18+
}
19+
}

src/main/java/rx/android/observables/AndroidObservable.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,23 @@
1515
*/
1616
package rx.android.observables;
1717

18-
import static rx.android.schedulers.AndroidSchedulers.mainThread;
19-
20-
import android.content.SharedPreferences;
21-
import rx.Observable;
22-
import rx.functions.Func1;
23-
import rx.android.operators.OperatorBroadcastRegister;
24-
import rx.android.operators.OperatorConditionalBinding;
25-
import rx.android.operators.OperatorLocalBroadcastRegister;
26-
2718
import android.app.Activity;
2819
import android.app.Fragment;
2920
import android.content.Context;
3021
import android.content.Intent;
3122
import android.content.IntentFilter;
23+
import android.content.SharedPreferences;
3224
import android.os.Build;
3325
import android.os.Handler;
34-
import rx.operators.OperatorSharedPreferenceChange;
26+
27+
import rx.Observable;
28+
import rx.android.operators.OperatorBroadcastRegister;
29+
import rx.android.operators.OperatorConditionalBinding;
30+
import rx.android.operators.OperatorLocalBroadcastRegister;
31+
import rx.android.operators.OperatorSharedPreferenceChange;
32+
import rx.functions.Func1;
33+
34+
import static rx.android.schedulers.AndroidSchedulers.mainThread;
3535

3636

3737
public final class AndroidObservable {

src/main/java/rx/android/observables/ViewObservable.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,21 @@
1515
*/
1616
package rx.android.observables;
1717

18+
import android.view.View;
19+
import android.widget.AdapterView;
20+
import android.widget.CompoundButton;
21+
import android.widget.TextView;
22+
1823
import rx.Observable;
1924
import rx.android.events.OnCheckedChangeEvent;
2025
import rx.android.events.OnClickEvent;
26+
import rx.android.events.OnItemClickEvent;
2127
import rx.android.events.OnTextChangeEvent;
28+
import rx.android.operators.OperatorAdapterViewOnItemClick;
2229
import rx.android.operators.OperatorCompoundButtonInput;
2330
import rx.android.operators.OperatorTextViewInput;
2431
import rx.android.operators.OperatorViewClick;
2532

26-
import android.view.View;
27-
import android.widget.CompoundButton;
28-
import android.widget.TextView;
29-
3033
public class ViewObservable {
3134

3235
public static Observable<OnClickEvent> clicks(final View view) {
@@ -53,4 +56,8 @@ public static Observable<OnCheckedChangeEvent> input(final CompoundButton button
5356
return Observable.create(new OperatorCompoundButtonInput(button, emitInitialValue));
5457
}
5558

59+
public static Observable<OnItemClickEvent> itemClicks(final AdapterView<?> adapterView) {
60+
return Observable.create(new OperatorAdapterViewOnItemClick(adapterView));
61+
}
62+
5663
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/**
2+
* Copyright 2014 Netflix, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package rx.android.operators;
17+
18+
import android.view.View;
19+
import android.widget.AbsListView;
20+
import android.widget.AdapterView;
21+
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
import java.util.Map;
25+
import java.util.WeakHashMap;
26+
27+
import rx.Observable;
28+
import rx.Subscriber;
29+
import rx.Subscription;
30+
import rx.android.events.OnItemClickEvent;
31+
import rx.android.observables.Assertions;
32+
import rx.android.subscriptions.AndroidSubscriptions;
33+
import rx.functions.Action0;
34+
35+
public class OperatorAdapterViewOnItemClick implements Observable.OnSubscribe<OnItemClickEvent> {
36+
37+
private final AdapterView<?> adapterView;
38+
39+
public OperatorAdapterViewOnItemClick(final AdapterView<?> adapterView) {
40+
this.adapterView = adapterView;
41+
}
42+
43+
@Override
44+
public void call(final Subscriber<? super OnItemClickEvent> observer) {
45+
Assertions.assertUiThread();
46+
final CompositeOnClickListener composite = CachedListeners.getFromViewOrCreate(adapterView);
47+
48+
final AbsListView.OnItemClickListener listener = new AdapterView.OnItemClickListener() {
49+
@Override
50+
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
51+
observer.onNext(new OnItemClickEvent(parent, view, position, id));
52+
}
53+
};
54+
55+
final Subscription subscription = AndroidSubscriptions.unsubscribeInUiThread(new Action0() {
56+
@Override
57+
public void call() {
58+
composite.removeOnClickListener(listener);
59+
}
60+
});
61+
62+
composite.addOnClickListener(listener);
63+
observer.add(subscription);
64+
}
65+
66+
private static class CompositeOnClickListener implements AbsListView.OnItemClickListener {
67+
private final List<AbsListView.OnItemClickListener> listeners = new ArrayList<AbsListView.OnItemClickListener>();
68+
69+
public boolean addOnClickListener(final AbsListView.OnItemClickListener listener) {
70+
return listeners.add(listener);
71+
}
72+
73+
public boolean removeOnClickListener(final AbsListView.OnItemClickListener listener) {
74+
return listeners.remove(listener);
75+
}
76+
77+
@Override
78+
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
79+
for (AdapterView.OnItemClickListener listener : listeners) {
80+
listener.onItemClick(parent, view, position, id);
81+
}
82+
}
83+
}
84+
85+
private static class CachedListeners {
86+
private static final Map<AdapterView<?>, CompositeOnClickListener> sCachedListeners = new WeakHashMap<AdapterView<?>, CompositeOnClickListener>();
87+
88+
public static CompositeOnClickListener getFromViewOrCreate(final AdapterView<?> view) {
89+
final CompositeOnClickListener cached = sCachedListeners.get(view);
90+
91+
if (cached != null) {
92+
return cached;
93+
}
94+
95+
final CompositeOnClickListener listener = new CompositeOnClickListener();
96+
97+
sCachedListeners.put(view, listener);
98+
view.setOnItemClickListener(listener);
99+
100+
return listener;
101+
}
102+
}
103+
}

src/main/java/rx/operators/OperatorSharedPreferenceChange.java renamed to src/main/java/rx/android/operators/OperatorSharedPreferenceChange.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package rx.operators;
16+
package rx.android.operators;
1717

1818
import android.content.SharedPreferences;
1919
import rx.Observable;

0 commit comments

Comments
 (0)