【问题标题】:RxJava as event bus?RxJava 作为事件总线?
【发布时间】:2015-09-24 17:20:06
【问题描述】:

我开始学习 RxJava,到目前为止我很喜欢它。我有一个片段与按钮单击时的活动进行通信(用新片段替换当前片段)。 Google 建议使用 interface 片段来与活动通信,但它太冗长了,我尝试使用广播接收器,它通常可以工作,但它有缺点。

由于我正在学习 RxJava,我想知道从片段到活动(或片段到片段)进行通信是否是一个不错的选择?如果是这样,使用 RxJava 进行此类通信的最佳方式是什么?我是否需要像one 这样制作事件总线,如果是这种情况,我应该制作一个总线实例并在全球范围内使用它(与主题一起)?

【问题讨论】:

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


    【解决方案1】:

    是的,在你学会了如何做之后,这真是太棒了。考虑以下单例类:

    public class UsernameModel {
    
        private static UsernameModel instance;
    
        private PublishSubject<String> subject = PublishSubject.create();
    
        public static UsernameModel instanceOf() {
            if (instance == null) {
                instance = new UsernameModel();
            }
            return instance;
        }
    
        /**
         * Pass a String down to event listeners.
         */
        public void setString(String string) {
            subject.onNext(string);
        }
    
        /**
         * Subscribe to this Observable. On event, do something e.g. replace a fragment
         */
        public Observable<String> getStringObservable() {
            return subject;
        }
    
    }
    

    在您的 Activity 中准备好接收事件(例如,将其放在 onCreate 中):

    UsernameModel usernameModel = UsernameModel.instanceOf();
    
    //be sure to unsubscribe somewhere when activity is "dying" e.g. onDestroy
    subscription = usernameModel.getStringObservable()
            .subscribe(s -> {
                // Do on new string event e.g. replace fragment here
            }, throwable -> {
                // Normally no error will happen here based on this example.
            });
    

    在你 Fragment 发生的时候把事件传递下去:

    UsernameModel.instanceOf().setString("Nick");
    

    然后您的活动将做一些事情。

    提示 1:使用您喜欢的任何对象类型更改字符串。

    提示 2:如果您有依赖注入,它也很有效。


    更新: 我写了一个比较长的article

    【讨论】:

    • 1.你的例子最好使用BehaviorSubject 来观察这个“粘性”。即新订阅将看到最后一个值。您可能希望这样,因为依赖于该值的新视图将在订阅时正确更新。 2. UsernameModel 真的只做一件事:包装 PublishSubject 并使其成为单例。 DI 提供单例!如果您使用 DI,您只需直接注入 PublishSubjectBehaiorSubject。如果你使用 Dagger,那么你可以使用@Named("username") 注入Subject
    • 类似实现check below answer
    【解决方案2】:

    目前我认为我对这个问题的首选方法是:

    1.) 不要使用一个全局总线来处理整个应用程序中的所有事情(因此变得相当笨拙),而是使用“本地”总线来明确定义的目的,并且只将它们插入您需要它们的地方。

    例如,您可能有:

    • 一条总线用于在您的 Activitys 和您的 ApiService 之间发送数据。
    • 一个总线用于在Activity 中的多个Fragments 之间进行通信。
    • 一条总线将当前选定的应用主题颜色发送给所有Activitys,以便他们可以相应地为所有图标着色。

    2.) 使用 Dagger(或者如果您愿意,也可以使用 AndroidAnnotations)来减少将所有东西连接在一起的痛苦(并且还可以避免大量 static 实例)。这也使得它更容易,例如。 G。有一个组件只处理在SharedPreferences 中存储和读取登录状态 - 然后此组件也可以直接连接到您的ApiService 以提供所有请求的会话令牌。

    3.) 可以在内部随意使用 Subjects,但在通过调用 return subject.asObservable() 将它们分发给公众之前将它们“投射”到 Observable。这可以防止其他类将值推送到不应被允许的Subject

    【讨论】:

    • 我真的很想知道,拥有多个事件总线实例有什么意义?它无助于高凝聚力。您最终将获得同一事物的多个实例,而不是一个实例,而没有任何实际好处。
    • @Gunhan 少转转。特定的总线具有特定的通信模型。如果您需要监听“SomeObject”的变化,为什么要通过“SomeOtherObject”可能正在行驶的同一总线发送 SomeObjects。混凝土公交车是特定信息的专用多层车道。
    【解决方案3】:

    定义事件

    public class Trigger {
    
    public Trigger() {
    }
    
    public static class Increment {
    }
    
    public static class Decrement {
    }
    
    public static class Reset {
    }
    }
    

    事件控制器

    public class RxTrigger {
    
    private PublishSubject<Object> mRxTrigger = PublishSubject.create();
    
    public RxTrigger() {
        // required
    }
    
    public void send(Object o) {
        mRxTrigger.onNext(o);
    }
    
    public Observable<Object> toObservable() {
        return mRxTrigger;
    }
    // check for available events
    public boolean hasObservers() {
        return mRxTrigger.hasObservers();
    }
    }
    

    应用程序类

    public class App extends Application {
    
    private RxTrigger rxTrigger;
    
    public App getApp() {
        return (App) getApplicationContext();
    }
    
    @Override
    public void onCreate() {
        super.onCreate();
        rxTrigger = new RxTrigger();
    }
    
    
    public RxTrigger reactiveTrigger() {
        return rxTrigger;
    }
    
    
    }
    

    在需要的地方注册事件监听器

                   MyApplication mApp = (App) getApplicationContext();
                   mApp
                        .reactiveTrigger() // singleton object of trigger
                        .toObservable()
                        .subscribeOn(Schedulers.io()) // push to io thread
                        .observeOn(AndroidSchedulers.mainThread()) // listen calls on main thread
                        .subscribe(object -> { //receive events here
                            if (object instanceof Trigger.Increment) {
                                fabCounter.setText(String.valueOf(Integer.parseInt(fabCounter.getText().toString()) + 1));
                            } else if (object instanceof Trigger.Decrement) {
                                if (Integer.parseInt(fabCounter.getText().toString()) != 0)
                                    fabCounter.setText(String.valueOf(Integer.parseInt(fabCounter.getText().toString()) - 1));
                            } else if (object instanceof Trigger.Reset) {
                                fabCounter.setText("0");
                            }
                        });
    

    发送/触发事件

     MyApplication mApp = (App) getApplicationContext();
     //increment
     mApp
        .reactiveTrigger()
        .send(new Trigger.Increment());
    
     //decrement
     mApp
        .reactiveTrigger()
        .send(new Trigger.Decrement());
    

    以上库的完整实现示例 -> RxTrigger

    【讨论】:

    • subscribeOn(Schedulers.io())的目的是什么?
    • 它是可选的,subscribeOn,observeOn,除非你想在后台线程中执行一些操作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-24
    • 1970-01-01
    相关资源
    最近更新 更多