【问题标题】:Differentiate between several events on the same Eventbus区分同一 Eventbus 上的多个事件
【发布时间】:2018-02-19 00:14:15
【问题描述】:

我使用 MVP 模式创建了一个应用程序,我找到了这个教程 link 并决定在我的应用程序中实现它,以便片段与它们的活动通信。为了仍然使用 MVP 模式,我将 Eventbus 的实现移至相应的活动展示器和片段展示器。现在我面临一个新问题,我的一个片段需要更改活动参数中的两件事(工具栏相关和 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) 添加另一个 evenbus,但我认为为每个要回调活动的事件设置单独的 eventbus 是不合逻辑的。

感谢您的帮助

更新

我遇到了另一个问题(或者至少是潜在的问题)。我添加了一个 SwipeRefreshLayout 来包装我的内容(这是框架布局,我将拥有的每个片段都将显示在此容器中)。我这样做的主要原因是在活动和所有片段之间实现单个接口。假设您没有网络连接,我将向用户显示一条消息,让其向下滑动以尝试刷新当前片段。到目前为止,我已经通过将 SwipeRefreshLayout 添加到我拥有的每个片段来完成此操作。它基本上是相同的代码,我想将所有代码合并到活动中的一个位置。我很想使用 EventBus,但据我了解,我需要将所有片段订阅到“事件”onRefresh。 如何将事件发送到适当的片段?

【问题讨论】:

  • 这个事件总线实现有点复杂。您可以只拥有一个主题并让它发布。接下来,你的消息对象应该包含两个值,即 int 或 String 事件,T 值。然后在您的订阅者中,您可以在 switch case 中检查事件并相应地转换您的值
  • 你能举个例子来说明如何实现它,我还需要发送几个参数,我想发送一个包但我怀疑它是在片段和活动之间发送数据的最佳解决方案
  • 现在最好的交互方式是通过数据绑定、视图模型和实时数据。这些功能非常强大developer.android.com/topic/libraries/architecture/… 但是我将提供有关 rxBus 的答案

标签: android mvp event-bus


【解决方案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{...})

记得在销毁时处理处置。

【讨论】:

  • 如何在您的解决方案中发送多个参数?
  • ActionEvent 采取一个动作,事件可以是任何对象。您可以创建一个具有多个变量的类,并将其对象值传递或传递 Map 对象。在订阅者或观察者中,您可以通过它的操作来检查事件,最好是在 switch case 中,并获取相应的值。
  • 如果我将创建一个包装类,该类将包含操作(以知道要执行什么操作)和一个捆绑包或地图,如果有任何我需要考虑的参数,会不会像您的解决方案还是您的解决方案有其他优势?,我更新了我的主要帖子,提出了另一个关于 EventBus 的问题
  • 就可以了。但是您正在为每个操作创建主题,您可以只使用一个,并且您的包装类应该是通用的(就像我在这里所做的一样),以便您可以将它放在 switch 案例中。这就是我的想法,现在,如果您发现任何更好的方法,我将很乐意遵循,因为我的实现仍然有一些限制。
猜你喜欢
  • 1970-01-01
  • 2021-10-03
  • 2013-08-17
  • 1970-01-01
  • 2022-07-15
  • 2022-11-30
  • 2018-02-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多