2016-04-12 7 views
4

Ich implementiere einen Event-Bus (RxBus) mit RxJava.RxJava als Event-Bus, onNext wird mehrmals aufgerufen, wenn nur ein Event-Post

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

Eine Veranstaltung von viewHolder eines RecyclerView

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

die Ereignisse von Fragment Abonnieren

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

Das Problem ist: Wenn ich auf itemView oder TagImageButton klicke, wird RxBus.post() nur einmal aufgerufen (was korrekt ist), aber Action1 call() wird mehrmals aufgerufen (nicht einmal konstante Zeiten). Bitte beachten Sie das Protokoll unten.

D/**-CardContentView(31177): Apr12, item clicked. 
D/**-RxBus(31177): Apr12, post event: com.*****[email protected] 
D/**-CardDetailFragment(31177): Apr12, call event: com.*****[email protected] 
D/**-CardDetailFragment(31177): Apr12, call event: com.*****[email protected] 
D/**-CardDetailFragment(31177): Apr12, call event: com.*****[email protected] 

Wie kann ich es nur einmal aufrufen?

EDIT: Ich fand, dass, wenn Action1 call() N mal dieses Mal aufgerufen wird, wird es N + 1 mal beim nächsten Mal aufgerufen werden, wenn ich auf dem Artikel klicken. Es scheint, dass das Observable alle nachfolgend beobachteten Elemente in der Geschichte an den Abonnenten aussendet.

+0

Wie viele 'mItemClickSubscription' haben Sie erstellt? – srain

+0

@srain nur ein 'mItemClickSubscription'. Eigentlich wird "mItemClickSubscription" erst verwendet, wenn "unsubscribe()" beendet wird. –

+0

Wie viele 'Fragmente' hast du erstellt? Wo ist deine 'unsubscribe()' Methode? – srain

Antwort

4

Endlich die Lösung finden.

Sehr einfach: Ich hätte mItemClickSubscription.unsubscribe(); und in onStop() genannt werden sollen.

PublishSubject wird im Ereignisbus verwendet. PublishSubject ist ein Thema:

Betreff, dass, sobald ein Beobachter abonniert hat, alle nachfolgend beobachteten Elemente an den Abonnenten sendet.

Also, wenn Sie nicht unsubscribe() das Abonnement zu tun, wird dieses Abonnement halten „Aufzeichnen“ alle Ereignisse in der Geschichte passiert ist, und gibt sie alle einmal .subscribe(onNext) ausgeführt wird.

+0

Super! Ich habe das gleiche Problem bei Android. Danke für das Teilen. –

Verwandte Themen