3

我正在将新的Mosby MVI库用于新的演示应用程序。在演示者中定义意图时,在附加视图时触发/发出意图时不一致。

例如:让我们在一个活动中定义非常简单的意图

public Observable<Boolean> intentLoadData(){
  return Observable.just(true);
}

演示者将意图绑定如下:

@Override
protected void bindIntents() {
  Observable<MailListViewState> loadData = intent(ExampleViewContract::intentLoadData).flatMap(interactor::loadData)
            .observeOn(AndroidSchedulers.mainThread());
  subscribeViewState(loadData, ExampleViewContract::render);
}

这个意图工作得很好。当导航到不同的活动(详细视图)并返回时,bindIntents()称为重新创建意图。intentLoadData()不会发出新项目,MviBasePresenter 将使用内部 BehaviorSubject 提供以前的 ViewState。

我的问题是:当我稍微调整意图(用于重新加载数据)时。当重新附加视图时,意图开始发出一个项目。

因此,让我们将意图更改为:

private PublishSubject<Boolean> mReloadDataSubject = PublishSubject.create();

private void reloadData(){
  mReloadDataSubject.onNext(true);
}

public Observable<Boolean> intentLoadData(){
  return mReloadDataSubject.startWith(true);
}

导航到新活动并返回时不。重新附加视图时,意图会发出一个新项目。在我的情况下,这会导致对后端的新 APU 调用以重新加载数据,而不是重用最后一个 ViewState。即使reloadData()从未调用过,也会发生这种情况。

这种行为感觉非常不一致。在重新附加视图期间触发意图时,我如何才能感觉更有控制力?

更新: 对我来说更有趣的是,如何避免在重新附加时自动发出意图,而无需完成 Observable。随着 PublishSubject 的引入,活动将重新加载整个数据,即使只是在旋转时也是如此。

4

2 回答 2

2

为了回答我自己的问题并总结评论,这是我的解决方案:

首先我们要了解 Mosby3 MVI 是如何恢复视图的,例如:旋转后,来回导航到不同的视图。Mosby3 保留了演示者的实例。当创建视图的新实例时,演示者将被恢复并附加到视图。onStart()在新视图中,演示者将更新意图。PublishSubject因此,新视图会创建新的意图,并且演示者将使用s订阅它们。

如果发出前一个视图的意图,onComplete()PublishSubject也完成并且流关闭。绑定到此意图的(交互器)逻辑将被取消订阅。因此,这个意图不能再被视图触发。

在原始问题的示例中。Observable.just(true)关闭流。即使重新创建视图及其意图(旋转后),也不会发出新项目。 mReloadDataSubject.startWith(true)而是不发出onComplete(),流是t closed. When the presenter resubscribes to that intent (after rotation), the intent emits thestartsWith(true)`。在示例中,这会导致每次旋转时都重新加载数据。

为了触发条件重新加载的意图,RxNavi非常有帮助。

public Observable<Boolean> intentReloadData() {
     //check if the data needs a reload in onResume()
     return RxNavi.observe(this, Event.RESUME)
                  .filter(ignored -> mNeedsReload == true)
                  .map(ignored -> true);
}
于 2017-02-22T09:53:06.270 回答
1

Mosby MVI 尊重 Reactive Streams 合同。看一眼intentLoadData()

public Observable<Boolean> intentLoadData(){
  return Observable.just(true);
}

Observable.just(true)不仅调用onNext(true)而且调用onCompleted()。一旦 Reactive 流完成,就不能通过流发出更多的项目。在onComplete()可观察流永久关闭后。

在这种情况下使用 aPublishSubject非常好,但为了更好的可读性,我建议不要使用startWith()而是做这样的事情:

public class MyActivity extends MviActivity<MyView, MailListViewState> {
  private PublishSubject<Boolean> mReloadDataSubject = PublishSubject.create();

  public void onResume(){
    super.onResume();
   // Triggers on screen orientation changes and
   // when navigating back to this screen from back stack
    mReloadDataSubject.onNext(true);
  }

  public Observable<Boolean> intentLoadData(){
    return mReloadDataSubject;
  }

}

顺便提一句。你也可以使用像Trello 的Navi这样的库,它为生命周期事件提供 Observable 流,但请记住,onCompleted()如果 Activity 被销毁(即在屏幕方向更改期间),Navi 会发出一个事件,所以你最终会遇到同样的情况:你必须onCompleted()如果您想稍后再次触发意图,请确保不会调用它。

于 2017-02-20T14:32:49.943 回答