如何使用RxJava处理回收站视图的项目点击

时间:2016-04-08 10:45:17

标签: android android-recyclerview rx-java rx-android

我有兴趣了解回复商品点击回收商视图的最佳方式是什么。

通常我会向ViewHolder添加一个onclick()侦听器,并通过接口将结果传回活动/片段。

我想在onBindViewHolder中添加一个Observable,但我不想为每个项目绑定创建一个新的Observable。

5 个答案:

答案 0 :(得分:12)

您可以使用RxBinding然后在适配器内创建一个主题,然后将所有事件重定向到该主题,只需创建一个主题的getter作为一个observable,最后只需订阅该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;
}

用法示例可能是:

mMyAdapter.getViewClickedObservable()
        .subscribe(view -> /* do the action. */);

答案 1 :(得分:0)

步骤1:将业务逻辑从活动中移出到域类/服务

可选:使用https://github.com/roboguice/roboguice轻松地相互连接服务。

第2步:@Inject(或只是设置)您的服务到您的适配器

第3步:抓住https://github.com/JakeWharton/RxBinding并使用适配器中的超能力:

RxView.clicks(button).subscribe(new Action1<Void>() {
    @Override
    public void call(Void aVoid) {
        myCoolService.doStuff();
    }
});

第4步:获取运行时崩溃并了解如何处理订阅

第5步:利润:)

答案 2 :(得分:0)

我建议你在点击时使用每个元素的初始方法,但为了避免每次只使用缓存缓存第一次发出的项目时创建一个新的observable。

      /**
 * 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));

}

答案 3 :(得分:0)

除了使用EventBus模型之外,我的解决方案非常像@epool。

首先,创建一个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(); }
}

然后,您有两种方法可以使用RxBus。使用RxBus引用创建自定义Application类,或在Activity / Fragment中创建RxBus,然后将其传递给适配器。我使用第一个。

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; }
}

然后使用

MyApp.get().bus() 

获取RxBus实例。

在Adpater中使用RxBus是这样的:

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(...)); }
                    });      
    }
}

您可以使用_bus.send()发送任何类,我们将在活动中收到:

RxBus bus = MyApp.get().bus();  // get the same RxBus instance
_sub = bus.toObserverable()
            .subscribe(e -> doSomething((SomeEvent) e));

关于取消订阅。

在MyRecyclerAdapter中,在clearup()方法中调用_sub.unsubscribe(),并在Activity的onDestory()中调用_sub.unsubscribe()。

@Override
public void onDestroy() {
    super.onDestroy();
    if (_adapter != null) {
        _adapter.cleanup();
    }
    if (_sub != null) {
         _sub.unsubscribe()
    }
}

答案 4 :(得分:0)

我们通常需要点击索引列表中的Pojo / Model类。我是按照以下方式做的:

1)创建BaseRecyclerViewAdapter

abstract class BaseRecyclerViewAdapter<T> : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    private val clickListenerPublishSubject = PublishSubject.create<T>()

    fun observeClickListener(): Observable<T> {
        return clickListenerPublishSubject
    }

    fun performClick(t: T?) {
        t ?: return
        clickListenerPublishSubject.onNext(t)
    }
}

2)在任何适配器中(例如MyAdapter

class MyAdapter(private val events: List<Event>, context: Context) : BaseRecyclerViewAdapter<Event>() {
    //... Other methods of RecyclerView
    override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {
        if (holder is EventViewHolder) {
            holder.eventBinding?.eventVm = EventViewModel(events[position])

            holder.eventBinding?.root?.setOnClickListener({ _ ->
                // This notifies the subscribers
                performClick(events[position])
            })
        }
    }
}

3)在需要点击监听器的ActivityFragment内部

myAdapter?.observeClickListener()
                ?.subscribe({ eventClicked ->
                    // do something with clicked item

                })