使用RxJava和EventBus将事件发送回活动/片段

时间:2018-04-06 17:04:10

标签: android kotlin rx-java reactive-programming event-bus

Android Studio 3.2 Canary 8
com.squareup:otto:1.3.8
io.reactivex:rxjava:1.3.7
kotlin 1.2.31

我正在尝试使用otto EventBus将事件发送回我的A​​ctivity。

但是,我正在使用RxJava执行一些后台工作,并且需要在第一个完成后发送事件。然而,在发布事件后。活动永远不会收到它。

此事件必须在主线程上执行此操作。 RxJava位于IO线程上。我不确定最好的方法是什么:

这是执行RxJava和EventBus帖子的交互器的代码

class Interactors(private val eventBus: Bus) {
    fun transmitMessage(): Completable {
        return insertTransmission()
                .andThen(onTransmissionChanged()) /* Send event to the activity */
                .andThen(requestTransmission())
    }

    private fun insertTransmission(): Completable {
        return Completable.fromCallable {
            Thread.sleep(4000)
            System.out.println("insertTransmission doing some long operation")
        }
    }

    private fun requestTransmission(): Completable {
        return Completable.fromCallable {
            Thread.sleep(2000)
            System.out.println("requestTransmission doing some long operation")
        }
    }

    /* Need to send this event back to the activity/fragment */
    private fun onTransmissionChanged(): Completable {
        return Completable.fromCallable {
            System.out.println("onTransmissionChanged send event to activity")
            eventBus.post(TransmissionChanged())
        }
    }
}

的活动:

public class HomeActivity extends AppCompatActivity {
    private Bus eventBus = new Bus();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);

        eventBus.register(this);

        new Interactors(eventBus).transmitMessage()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe();
    }

    @Override
    protected void onDestroy() {
        eventBus.unregister(this);
        super.onDestroy();
    }

    @Subscribe
    public void onTransmissionChangedEvent(TransmissionChanged transmissionChanged) {
        System.out.println("onTransmissionChangedEvent");
    }
}

EventBus类:

class TransmissionChanged

这是我运行应用程序时的输出:

insertTransmission doing some long operation
onTransmissionChanged

我不确定eventBus.post(..)是否阻止。实际上这应该在主线程中完成,就像回发到Activity以在UI中执行一些更新一样。

4 个答案:

答案 0 :(得分:2)

真的需要混合使用EventBusRxJava吗?对我来说,这会带来额外的复杂性而不会带来很多好处。您的用例似乎是使用Rx流的完美示例,对每个发射做了一些工作(在您通过onTransmissionChangedEvent()更新UI的情况下)。

我将transmitMessage()方法更改为以下内容:

fun transmitMessage(): Observable<TransmissionChanged> {
    return Observable.create(ObservableOnSubscribe<TransmissionChanged> { emitter ->
        insertTransmission()

        emitter.onNext(TransmissionChanged())  // perform this after the long running operation from insertTransmission() has finished

        requestTransmission()

        emitter.onComplete()   // after the long running operation from requestTransmission() has finished
    })
}

我猜您需要一些额外的数据来相应地更新您的UI - 这封装在TransmissionChanged类中 - 包括您需要的任何内容。需要注意的一件事 - 在RxJava中使用Observable.create()是危险的。我不记得这样做的安全方法是什么,并且没有用RxJava 1进行实验的项目...但是那里是Observable类中的工厂方法,可以安全地完成工作。

使用上述内容,您的Activity代码也变得更加清晰。由于所有操作都是通过单个Rx流处理的,因此不再需要Otto

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_home);

    new Interactors()
        .transmitMessage()
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(transmission -> onTransmissionChangedEvent(transmission),
                throwable -> handleError(throwable),
                () -> handleCompletion()
        );
}

答案 1 :(得分:1)

不允许接收者指定它想要接收事件的线程是Otto的短暂来临。它强制所有调用都需要在同一个线程上(默认为主线程)。调用者可以使用正确的线程。我非常喜欢GreenRobot的EventBus。您可以使用注释更改要接收的线程。所以,我的第一个建议是,如果你还没有投入奥托,那就考虑改用EventBus

如果您无法修改所有事件总线代码,可以post通过分配Handler来回到主循环器。它既快速又简单,但感觉有点像走出rx框架。

private fun onTransmissionChanged(): Completable {
    return Completable.fromCallable {
        System.out.println("onTransmissionChanged send event to activity")
        Handler(Looper.getMainLooper()).post {
            eventBus.post(TransmissionChanged())
        }
    }
}

如果您要调用很多内容,可能需要缓存Handler并将其传递给Interactors构造函数。

如果您想坚持使用RxJava调度程序,可以将Scheduler传递给构造函数,以指示您要在哪里执行后台工作,而不是使用subscribeOn。在transmitMessage中,使用它安排后台操作,同时强制eventBus.post到主线程,如下所示 -

class Interactors(private val eventBus: Bus, private val scheduler: Scheduler) {
    fun transmitMessage(): Completable {
        return insertTransmission()
                .subscribeOn(scheduler)
                .observeOn(AndroidSchedulers.mainThread())
                .andThen(onTransmissionChanged()) /* Send event to the activity */
                .observeOn(scheduler)
                .andThen(requestTransmission())
    }
    // Rest of the class is unchanged

}

在这种情况下,您将在HomeActivity中使用它,如下所示 -

new Interactors(eventBus, Schedulers.io()).transmitMessage()
              .observeOn(AndroidSchedulers.mainThread())
              .subscribe();

答案 2 :(得分:1)

在发布活动时,您的活动/片段可能未启动/附加,因此尚未注册到eventBus。由此事件发布,但没有订阅者(或者可能在其他地方还有其他订阅者)。 也许您应该使用Sticky Events使该事件“清醒”,这样您的活动/片段仍然可以处理它。

为了将EventBus事件用作RxJava代码,我执行以下操作:

public class EventBusRx {
    private static EventBusRx ourInstance = new EventBusRx();

    public static EventBusRx getInstance() {
        return ourInstance;
    }

    private EventBusRx() {}

    public final Subject<Integer> eventName = PublishSubject.create();`
}`

然后听这样的事件:

EventBusRx.getInstance().eventName
            .subscribeOn(AndroidSchedulers.mainThread())
            .doOnNext(o -> someAction())
            .subscribe();

发布活动:

public void postSomeEvent(int eventValue) {
    EventBusRx.getInstance().eventName.onNext(eventValue);
}

另请阅读有关RxJava的Replay,这可能对您有所帮助。

答案 3 :(得分:1)

您的活动/片段应包含此更新代码:

@Override
public void onResume() {
    super.onResume();
    if (!eventBus.isRegistered(this))
        eventBus.register(this);
}

@Override
public void onDestroy() {
    super.onDestroy();
    if (mEventBus.isRegistered(this))
        mEventBus.unregister(this);
}

@Subscribe(threadMode = ThreadMode.MAIN)
public void onTransmissionChangedEvent(TransmissionChanged transmissionChanged) {
    System.out.println("onTransmissionChangedEvent");
}

现在你的Interactors代码应该是这样的

new Interactors(eventBus).transmitMessage()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {

                @Override
                public void onSubscribe(Disposable d) {

                }

                @Override
                public void onNext(Object o) {
onTransmissionChanged();

                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onComplete() {

                }
            });

使用next on next方法调用onTransmissionChanged()。