rxandroid - rxjava2 android español
Cómo manejar Clics de Artículo para una vista de reciclador usando RxJava (4)
Me interesó averiguar cuál es la mejor manera de responder a un clic de elemento de una vista de reciclador.
Normalmente agregaría un oyente onclick () al ViewHolder y devolvería los resultados a la actividad / fragmento a través de una interfaz.
Pensé en agregar un Observable en el onBindViewHolder pero no quiero crear un nuevo Observable para cada enlace de artículo.
Paso 1: trasladar la lógica comercial de las actividades a clases / servicios de dominio
Opcional: utilice https://github.com/roboguice/roboguice para conectar fácilmente sus servicios entre sí.
Paso 2: @Inject
(o simplemente configure) su servicio en su adaptador
Paso 3: agarre https://github.com/JakeWharton/RxBinding
y use los super poderes en su adaptador:
RxView.clicks(button).subscribe(new Action1<Void>() {
@Override
public void call(Void aVoid) {
myCoolService.doStuff();
}
});
Paso 4: obtenga un fallo de tiempo de ejecución y aprenda a manejar suscripciones
Paso 5: GANANCIA :)
Le sugiero que haga con su aproximación inicial de un elemento observable por clic, pero para evitar crear un nuevo observable cada vez puede simplemente almacenar en caché los elementos emitidos la primera vez que utiliza el caché.
/**
* Here we can prove how the first time the items are delayed 100 ms per item emitted but second time becuase it´s cached we dont have any delay since
* the item emitted are cached
*/
@Test
public void cacheObservable() {
Integer[] numbers = {0, 1, 2, 3, 4, 5};
Observable<Integer> observable = Observable.from(numbers)
.doOnNext(number -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
})
.cache();
long time = System.currentTimeMillis();
observable.subscribe(System.out::println);
System.out.println("First time took:" + (System.currentTimeMillis() - time));
time = System.currentTimeMillis();
observable.subscribe(System.out::println);
System.out.println("Second time took:" + (System.currentTimeMillis() - time));
}
Mi solución era muy parecida a la de @epool, excepto el modelo EventBus.
Primero, crea un RxBus: RxBus.java
public class RxBus {
private final Subject<Object, Object> _bus = new SerializedSubject<>(PublishSubject.create());
public void send(Object o) { _bus.onNext(o); }
public Observable<Object> toObserverable() { return _bus; }
public boolean hasObservers() { return _bus.hasObservers(); }
}
Entonces, tienes dos formas de usar RxBus. Cree su clase de aplicación personalizada con la referencia RxBus o cree RxBus en Activity / Fragment y luego páselo al adaptador. Yo uso el primero.
MyApp.java
public class MyApp extends Application {
private static MyApp _instance;
private RxBus _bus;
public static MyApp get() { return _instance; }
@Override
public void onCreate() {
super.onCreate();
_instance = this;
_bus = new RxBus();
}
public RxBus bus() { return _bus; }
}
luego usa
MyApp.get().bus()
para obtener la instancia de RxBus.
El uso de RxBus en Adpater fue así:
public class MyRecyclerAdapter extends ... {
private RxBus _bus;
public MykRecyclerAdapter (...) {
....
_bus = MyApp.get().bus();
}
public ViewHolder onCreateViewHolder (...) {
_sub = RxView.longClicks(itemView) // You can use setOnLongClickListener as the same
.subscribe(aVoid -> {
if (_bus.hasObservers()) { _bus.send(new SomeEvent(...)); }
});
}
}
Puede enviar cualquier clase con _bus.send (), que recibiremos en la Actividad:
RxBus bus = MyApp.get().bus(); // get the same RxBus instance
_sub = bus.toObserverable()
.subscribe(e -> doSomething((SomeEvent) e));
Acerca de darse de baja
En MyRecyclerAdapter llame a _sub.unsubscribe () en los métodos clearup () y llame a _sub.unsubscribe () en Activity onDestory ().
@Override
public void onDestroy() {
super.onDestroy();
if (_adapter != null) {
_adapter.cleanup();
}
if (_sub != null) {
_sub.unsubscribe()
}
}
Puede usar RxBinding y luego crear un sujeto dentro de su adaptador, luego redireccionar todos los eventos a ese sujeto y simplemente crear un getter del sujeto para que actúe como un observable y finalmente solo suscribirse en ese observable.
private PublishSubject<View> mViewClickSubject = PublishSubject.create();
public Observable<View> getViewClickedObservable() {
return mViewClickSubject.asObservable();
}
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup pParent, int pViewType) {
Context context = pParent.getContext();
View view = (View) LayoutInflater.from(context).inflate(R.layout.your_item_layout, pParent, false);
ViewHolder viewHolder = new ViewHolder(view);
RxView.clicks(view)
.takeUntil(RxView.detaches(pParent))
.map(aVoid -> view)
.subscribe(mViewClickSubject);
return viewHolder;
}
Un ejemplo de uso podría ser:
mMyAdapter.getViewClickedObservable()
.subscribe(view -> /* do the action. */);