Android Studio 3.2 Canary 8
com.squareup:otto:1.3.8
io.reactivex:rxjava:1.3.7
kotlin 1.2.31
我正在尝试使用otto EventBus将事件发送回我的Activity。
但是,我正在使用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中执行一些更新一样。
答案 0 :(得分:2)
你真的需要混合使用EventBus
和RxJava
吗?对我来说,这会带来额外的复杂性而不会带来很多好处。您的用例似乎是使用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()。