Различие между несколькими событиями на одной и той же шине Eventbus

Я создал приложение, используя шаблон MVP, я нашел этот учебник ссылка и решил внедрить ее в свое приложение, чтобы фрагменты общались своими действиями. Я переместил реализацию Eventbus в соответствующий презентатор действий и презентатор фрагментов, чтобы по-прежнему использовать шаблон MVP. Теперь я столкнулся с новой проблемой: одному из моих фрагментов нужно изменить две вещи в параметрах активности (связанные с панелью инструментов и доступные для рисования ImageView). Могу ли я как-то различить, какой обратный вызов в функции принятия?

Класс RxBus

public final class RxBus {

    private static SparseArray<PublishSubject<Object>> sSubjectMap = new SparseArray<>();
    private static Map<Object, CompositeDisposable> sSubscriptionsMap = new HashMap<>();

    public static final int CHANGE_APP_BAR_LAYOUT = 0;
    public static final int CHANGE_POSTER_IMAGE = 1;

    @IntDef({CHANGE_APP_BAR_LAYOUT, CHANGE_POSTER_IMAGE})
    @interface Subject {
    }

    private RxBus() {
        // hidden constructor
    }

    /**
     * Get the subject or create it if it's not already in memory.
     */
    @NonNull
    private static PublishSubject<Object> getSubject(@Subject int subjectCode) {
        PublishSubject<Object> subject = sSubjectMap.get(subjectCode);
        if (subject == null) {
            subject = PublishSubject.create();
            subject.subscribeOn(AndroidSchedulers.mainThread());
            sSubjectMap.put(subjectCode, subject);
        }

        return subject;
    }

    /**
     * Get the CompositeDisposable or create it if it's not already in memory.
     */
    @NonNull
    private static CompositeDisposable getCompositeDisposable(@NonNull Object object) {
        CompositeDisposable compositeDisposable = sSubscriptionsMap.get(object);
        if (compositeDisposable == null) {
            compositeDisposable = new CompositeDisposable();
            sSubscriptionsMap.put(object, compositeDisposable);
        }

        return compositeDisposable;
    }

    /**
     * Subscribe to the specified subject and listen for updates on that subject. Pass in an object to associate
     * your registration with, so that you can unsubscribe later.
     * <br/><br/>
     * <b>Note:</b> Make sure to call {@link RxBus#unregister(Object)} to avoid memory leaks.
     */
    public static void subscribe(@Subject int subject, @NonNull Object lifecycle, @NonNull Consumer<Object> action) {
        Disposable disposable = getSubject(subject).subscribe(action);
        getCompositeDisposable(lifecycle).add(disposable);
    }

    /**
     * Unregisters this object from the bus, removing all subscriptions.
     * This should be called when the object is going to go out of memory.
     */
    public static void unSubscribe(@NonNull Object lifecycle) {
        //We have to remove the composition from the map, because once you dispose it can't be used anymore
        CompositeDisposable compositeDisposable = sSubscriptionsMap.remove(lifecycle);
        if (compositeDisposable != null) {
            compositeDisposable.dispose();
        }
    }

    /**
     * Publish an object to the specified subject for all subscribers of that subject.
     */
    public static void publish(@Subject int subject, @NonNull Object message) {
        getSubject(subject).onNext(message);
    }
}

Класс MainPresenter

public class MainPresenter extends BasePresenter<MainView> implements Observer<ConfigurationResponse>,Consumer<Object>
{
     ...
     @Override
     public void accept(Object o) throws Exception {
          //here is the problem how can I know if I should call to changeAppBar or change Image url?
     }

Класс ClientPresenter

public class ClientPresenter extends BasePresenter<SeriesSpecsView>
{
    ...

    //I'm calling to those function withing the fragment when the user click on the ui
    public void setPosterUrl(String posterUrl)
    {
        RxBus.publish(RxBus.CHANGE_POSTER_IMAGE,posterUrl);
    }

    public void setAppBarLayoutParams(boolean collapse)
    {
        RxBus.publish(RxBus.CHANGE_APP_BAR_LAYOUT,collapse);
    }
}

Я нашел два решения этой проблемы:

1) проверять объект, вызывая функцию instanceof, не очень эффективно, и нужно ли мне будет отправлять информацию одного и того же типа между двумя событиями?

2) Добавьте еще одну шину событий, но я не думаю, что логично иметь отдельную шину событий для каждого события, для которого вы хотите иметь обратный вызов для своей деятельности.

Спасибо за вашу помощь

ОБНОВЛЕНИЕ

Я столкнулся с другой проблемой (или, по крайней мере, потенциальной проблемой). Я добавил SwipeRefreshLayout, чтобы обернуть мой контент (который является макетом кадра, каждый фрагмент, который у меня будет, будет отображаться в этом контейнере). Моя основная причина сделать это заключалась в реализации единого интерфейса между активностью и всеми фрагментами. Допустим, у вас нет сетевого подключения. Я покажу пользователю сообщение, чтобы он провел пальцем вниз, чтобы попытаться обновить текущий фрагмент. До сих пор я делал это, добавляя SwipeRefreshLayout к каждому из имеющихся у меня фрагментов. По сути, это один и тот же код, и я решил объединить весь код в одном месте в действии. Я хотел бы использовать EventBus, но, насколько я понимаю, мне нужно будет подписаться на все фрагменты на «событие» onRefresh. Как я могу отправить событие в соответствующий фрагмент?


person Anton Makov    schedule 19.02.2018    source источник
comment
Эта реализация шины событий немного сложна. Вы могли бы просто иметь одну тему и позволить ее опубликовать. Далее, ваш объект сообщения должен содержать два значения, то есть событие int или String, значение T. Затем в своем подписчике вы можете проверить событие в случае переключения и соответственно указать свое значение.   -  person Debanjan    schedule 19.02.2018
comment
Можете ли вы привести пример того, как это реализовать, мне также нужно отправить несколько аргументов, я думал об отправке пакета, но я сомневаюсь, что это лучшее решение для отправки данных между фрагментом и активностью   -  person Anton Makov    schedule 19.02.2018
comment
Теперь лучший способ взаимодействия — это привязка данных, модель представления и оперативные данные. Это невероятно мощные developer.android.com/topic/libraries/architecture/. Однако я дам ответ о rxBus   -  person Debanjan    schedule 19.02.2018


Ответы (1)


Я использую RxBus для передачи глобальных событий. Вы также можете использовать это по-своему.

class RxBus {
    private val  busSubject: Subject<ActionEvent<out Any>> =
            PublishSubject.create()

    fun  register( onNext:
    Consumer<ActionEvent<out Any>>):Disposable{
        return busSubject
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(onNext)

    }


    fun post(event: ActionEvent<out Any>) {
        busSubject.onNext(event)
    }

}

open class ActionEvent<T>(val action: ActionEnum
                     , val event: T) {


}

Вы можете использовать String вместо ActionEnum, который является просто классом перечисления.

Когда вы публикуете что-то,

getRxBus()?.post(ActionEvent(ActionEnum.CHANGE_APP_BAR_LAYOUT,collapse))

Когда вы хотите подписаться,

val disposable = rxBus.subscribe(Consumer{...})

Не забудьте избавиться от удаления при уничтожении.

person Debanjan    schedule 19.02.2018
comment
Как я могу отправить несколько параметров с вашим решением? - person Anton Makov; 20.02.2018
comment
ActionEvent выполняет действие, и событием может быть любой объект. Вы можете создать класс с несколькими переменными и передать его объект в значении или передать объект карты. В подписчике или наблюдателе вы можете проверить событие по его действию, желательно в случае переключения, и взять соответствующее значение. - person Debanjan; 20.02.2018
comment
Если я создам класс-оболочку, который будет содержать действие (чтобы знать, какое действие выполнить) и пакет или карту, если есть какие-либо аргументы, которые мне нужно применить для рассмотрения, будет ли это похоже на ваше решение или есть другие преимущества вашего решения?, я обновил свой основной пост другим вопросом о EventBus - person Anton Makov; 20.02.2018
comment
Это сработает. Но вы создаете темы для каждого действия, вы можете просто использовать одну, и ваш класс-оболочка должен быть универсальным (то же самое, что я сделал здесь), чтобы вы могли поместить его в случай переключения. Вот что я думаю, теперь, если вы найдете лучший подход, я буду рад следовать, поскольку моя реализация все еще имеет некоторые ограничения. - person Debanjan; 20.02.2018