Mosby MVI:意图绑定行为不一致

时间:2017-02-20 13:31:03

标签: android mosby

我正在使用新的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。

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

所以我们将意图改为:

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的引入,即使只是旋转,活动也会重新加载整个数据。

2 个答案:

答案 0 :(得分:2)

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

首先,我们必须了解Mosby3 MVI如何恢复视图,例如:旋转后,前后导航到不同的视图。 Mosby3保留了演示者的实例。创建视图的新实例时,将恢复演示者并将其附加到视图。新视图的onStart(),演示者将更新意图。因此,新视图会创建新的意图,演示者将使用PublishSubject订阅它们。

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

在原始问题的例子中。 Observable.just(true)关闭了流。即使重新创建视图及其意图(旋转后),也不会发出新项目。 mReloadDataSubject.startWith(true)代替不会发出onComplete()并且流不是t closed. When the presenter resubscribes to that intent (after rotation), the intent emits the startsWith(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);
}

答案 1 :(得分:1)

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

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

Observable.just(true)不仅会调用onNext(true),还会调用onCompleted()。完成Reactive流后,不能通过流发出更多项。在onComplete()之后,可观察流将永久关闭。

在这种情况下使用PublishSubject完全没问题,但为了更好的可读性,我建议不要使用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流,但请记住,如果活动被销毁(即在屏幕方向更改期间),Navi会发出onCompleted()事件,因此您将结束在相同的情况下:如果您想稍后再次激活意图,则必须确保未调用onCompleted()