Skip to content

Instantly share code, notes, and snippets.

@aballano
Last active June 14, 2018 19:54
Show Gist options
  • Save aballano/92257b6348312b541aa4f6b205eb14e4 to your computer and use it in GitHub Desktop.
Save aballano/92257b6348312b541aa4f6b205eb14e4 to your computer and use it in GitHub Desktop.
Create an observable of long click events on RecyclerView items (refer to RxBinding tests for the whole picture).
import android.support.v7.widget.RecyclerView;
import android.view.View;
import rx.Observable;
import rx.Subscriber;
import rx.android.MainThreadSubscription;
import static rx.android.MainThreadSubscription.verifyMainThread;
final class RecyclerViewItemLongClickOnSubscribe implements Observable.OnSubscribe<Integer> {
final RecyclerView recyclerView;
public RecyclerViewItemLongClickOnSubscribe(RecyclerView recyclerView) {
this.recyclerView = recyclerView;
}
@Override public void call(final Subscriber<? super Integer> subscriber) {
verifyMainThread();
final View.OnLongClickListener onLongClickListener = new View.OnLongClickListener() {
@Override public boolean onLongClick(View view) {
if (!subscriber.isUnsubscribed()) {
RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(view);
subscriber.onNext(holder.getAdapterPosition());
return true;
}
return false;
}
};
final RecyclerView.OnChildAttachStateChangeListener onAttachListener = new RecyclerView.OnChildAttachStateChangeListener() {
@Override public void onChildViewAttachedToWindow(View view) {
view.setOnLongClickListener(onLongClickListener);
}
@Override public void onChildViewDetachedFromWindow(View view) {
view.setOnLongClickListener(null);
}
};
subscriber.add(new MainThreadSubscription() {
@Override protected void onUnsubscribe() {
recyclerView.removeOnChildAttachStateChangeListener(onAttachListener);
}
});
recyclerView.addOnChildAttachStateChangeListener(onAttachListener);
}
}
@RunWith(AndroidJUnit4.class)
public final class RxRecyclerViewTest {
@Rule public final ActivityTestRule<RxRecyclerViewTestActivity> activityRule =
new ActivityTestRule<>(RxRecyclerViewTestActivity.class);
private final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
RecyclerView view;
private ViewInteraction interaction;
private ViewDirtyIdlingResource viewDirtyIdler;
private View child;
@Before public void setUp() {
RxRecyclerViewTestActivity activity = activityRule.getActivity();
view = activity.recyclerView;
child = new View(activityRule.getActivity());
interaction = Espresso.onView(ViewMatchers.withId(android.R.id.primary));
viewDirtyIdler = new ViewDirtyIdlingResource(activity);
Espresso.registerIdlingResources(viewDirtyIdler);
}
@After public void tearDown() {
Espresso.unregisterIdlingResources(viewDirtyIdler);
}
@Test public void itemsClicked() {
RecordingObserver<Integer> o = new RecordingObserver<>();
Subscription subscription = RxRecyclerView.itemClick(view)
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(o);
o.assertNoMoreEvents();
final Adapter adapter = new Adapter();
instrumentation.runOnMainSync(new Runnable() {
@Override public void run() {
view.setAdapter(adapter);
}
});
for (int i = 0, childCount = view.getChildCount(); i < childCount; i++) {
final View childAt = view.getChildAt(i);
instrumentation.runOnMainSync(new Runnable() {
@Override public void run() {
childAt.performClick();
}
});
assertThat(o.takeNext()).isEqualTo(i);
}
subscription.unsubscribe();
instrumentation.runOnMainSync(new Runnable() {
@Override public void run() {
view.getChildAt(0).performClick();
}
});
o.assertNoMoreEvents();
}
@Test public void itemsLongClicked() {
RecordingObserver<Integer> o = new RecordingObserver<>();
Subscription subscription = RxRecyclerView.itemLongClick(view)
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(o);
o.assertNoMoreEvents();
final Adapter adapter = new Adapter();
instrumentation.runOnMainSync(new Runnable() {
@Override public void run() {
view.setAdapter(adapter);
}
});
for (int i = 0, childCount = view.getChildCount(); i < childCount; i++) {
final View childAt = view.getChildAt(i);
instrumentation.runOnMainSync(new Runnable() {
@Override public void run() {
childAt.performLongClick();
}
});
assertThat(o.takeNext()).isEqualTo(i);
}
subscription.unsubscribe();
instrumentation.runOnMainSync(new Runnable() {
@Override public void run() {
view.getChildAt(0).performLongClick();
}
});
o.assertNoMoreEvents();
}
private static class Adapter extends RecyclerView.Adapter<ViewHolder> {
public Adapter() {
setHasStableIds(true);
}
@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
TextView v = (TextView) LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
return new ViewHolder(v);
}
@Override public void onBindViewHolder(ViewHolder holder, int position) {
holder.textView.setText(String.valueOf(position));
}
@Override public int getItemCount() {
return 100;
}
@Override public long getItemId(int position) {
return position;
}
}
private static class ViewHolder extends RecyclerView.ViewHolder {
TextView textView;
public ViewHolder(TextView itemView) {
super(itemView);
this.textView = itemView;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment