【问题标题】:RxJava as an event bus, onNext is called multiple times when only one event postRxJava 作为事件总线,只有一个事件发布时会多次调用 onNext
【发布时间】:2016-04-12 07:40:04
【问题描述】:

我正在使用 RxJava 实现事件总线 (RxBus)。

RxBus.java

public class RxBus {

    private static final String TAG = LogUtils.makeTag(RxBus.class);
    private static final RxBus INSTANCE = new RxBus();

    private final Subject<Object, Object> mBusSubject = new SerializedSubject<>(PublishSubject.create());

    public static RxBus getInstance() {
        return INSTANCE;
    }

    public <T> Subscription register(final Class<T> eventClass, Action1<T> onNext) {
        return mBusSubject
                .filter(new Func1<Object, Boolean>() {
                    @Override
                    public Boolean call(Object event) {
                        return event.getClass().equals(eventClass);
                    }
                })
//                .filter(event -> event.getClass().equals(eventClass))
                .map(new Func1<Object, T>() {
                    @Override
                    public T call(Object obj) {
                        return (T) obj;
                    }
                })
//                .map(obj -> (T) obj)
                .subscribe(onNext);
    }

    public void post(Object event) {
        Log.d(TAG, "Apr12, " + "post event: " + event);
        mBusSubject.onNext(event);
    }
}

从 RecyclerView 的 viewHolder 发布事件

public ViewHolder(LayoutInflater inflater, final ViewGroup parent) {
        super(inflater.inflate(R.layout.bill_card, parent, false));

        drawee = (SimpleDraweeView) itemView.findViewById(R.id.card_image);
        title = (TextView) itemView.findViewById(R.id.card_title);

        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Log.d(TAG, "Apr12, item clicked.");
                RxBus.getInstance().post(new ItemSelectedEvent(position));
            }
        });

        TagImageButton = (ImageButton) itemView.findViewById(R.id.tag_button);
        TagImageButton.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                Log.d(TAG, "Tag button clicked.");
                RxBus.getInstance().post(new ApplyTagForItemEvent(position));
            }
        });
    }
}

从 Fragment 订阅事件

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    mActivity = getActivity();
    Log.d(TAG, "getActivity(): " + getActivity());
    mItemClickSubscription = RxBus.getInstance().register(ItemSelectedEvent.class,
            new Action1<ItemSelectedEvent>() {
                @Override
                public void call(ItemSelectedEvent event) {
                    Log.d(TAG, "Apr12, " + "call event: " + event);
                    if (mDetail == null) {
                        if (getParentFragment() instanceof IFragmentStackHolder) {
                            IFragmentStackHolder fsh = (IFragmentStackHolder) getParentFragment();

                            Fragment details = new DetailCardFragment();
                            Bundle args = new Bundle();
                            args.putInt(ContentHolder.INDEX, event.getPosition());
                            details.setArguments(args);

                            fsh.pushFragment(details, event.getPairs());
                        }
                    }
                }
            });

    mApplyTagSubscription = RxBus.getInstance().register(ApplyTagForItemEvent.class,
            new Action1<ApplyTagForItemEvent>() {
                @Override
                public void call(ApplyTagForItemEvent event) {
                    IFragmentStackHolder fsh = (IFragmentStackHolder) getParentFragment();

                    Fragment tagApplyFragment = new TagApplyFragment();
                    Bundle args = new Bundle();
                    args.putInt(ContentHolder.INDEX, event.getPosition());
                    tagApplyFragment.setArguments(args);

                    fsh.pushFragment(tagApplyFragment, null);
                }
            }
    );
}

问题是:当我点击itemViewTagImageButton 时,RxBus.post() 只被调用一次(这是正确的),但Action1 call() 被调用多次(甚至不是恒定时间)。请参阅下面的日志。

D/**-CardContentView(31177): Apr12, item clicked.
D/**-RxBus(31177): Apr12, post event: com.*****.events.ItemSelectedEvent@1a11346e
D/**-CardDetailFragment(31177): Apr12, call event: com.*****.events.ItemSelectedEvent@1a11346e
D/**-CardDetailFragment(31177): Apr12, call event: com.*****.events.ItemSelectedEvent@1a11346e
D/**-CardDetailFragment(31177): Apr12, call event: com.*****.events.ItemSelectedEvent@1a11346e

我怎样才能让它只调用一次?

编辑:我发现如果Action1 call()这次被调用了N次,下次点击item的时候会被调用N+1次。似乎 observable 正在向订阅者发送历史中所有后续观察到的项目。

【问题讨论】:

  • 你创建了多少mItemClickSubscription
  • @srain 只有一个mItemClickSubscription。实际上mItemClickSubscription直到unsubscribe()才被使用。
  • 你创建了多少个Fragment?你的unsubscribe() 方法在哪里?
  • @srain 到目前为止,只有这个片段订阅了这个事件。我还没有打电话给unsubscribe()。我打算在onDestroy()onStop()中做unsubscribe(),但我认为它对我得到的错误没有影响。
  • @srain 天哪……这正是问题所在。我需要在onStop() 中调用unsubscribe(),这样之前处理的事件就不会再次发出。谢谢你的提示!

标签: android rx-java rx-android event-bus


【解决方案1】:

终于找到解决办法了。

非常简单:我应该在onStop() 中调用mItemClickSubscription.unsubscribe();mApplyTagSubscription.unsubscribe();

PublishSubject 用于事件总线。 PublishSubject 是一个主题:

一旦观察者订阅,主题就会向订阅者发出所有后续观察到的项目。

所以如果你不unsubscribe()订阅,这个订阅会一直“记录”历史中发生的所有事件,并在.subscribe(onNext)被执行后发出所有事件。

【讨论】:

  • 太棒了!我在android中遇到了同样的问题。感谢分享。
  • 这里不是 BehaviorSubject 更好的选择吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-04
  • 1970-01-01
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多