【问题标题】:Mosby MVI: Inconsistent intent binding behaviorMosby MVI:意图绑定行为不一致
【发布时间】:2017-02-20 13:31:03
【问题描述】:

我正在将新的 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(用于重新加载数据)时。当重新附加视图时,意图开始发出一个项目。

所以让我们将意图更改为:

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

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

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

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

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

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

【问题讨论】:

    标签: android mosby


    【解决方案1】:

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

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

    如果前一个视图的意图发出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);
    }
    

    【讨论】:

      【解决方案2】:

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

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

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

      在这种情况下使用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() 事件,因此您最终会处于相同的状态情况:如果您想稍后再次触发 Intent,则必须确保不调用 onCompleted()

      【讨论】:

      • 我的问题恰恰相反。使用 PublishSubject 有助于随后触发意图,但是在重新附加视图时如何阻止它在 bindIntents() 中发出?
      • “重新附加视图”是什么意思?能举个具体的例子吗?
      • 我使用 PublishSubject 定义从 Web 服务加载数据,就像我原来的问题一样。活动开始,数据将被加载。当我旋转设备时,在 MviBasePresenter 中的bindIntentActually() 期间再次触发加载意图。我想避免这种不必要的重新加载。在这种情况下,bindIntentActually()attachView() 中被调用,viewAttachedFirstTime 设置为 false。这就是为什么我指的是重新附加。
      • 所以你只想开火一次?然后在发出一次意图后完成,例如Observable.just(true)
      • 类似这样的东西:Observable.merge(initialLoadingIntent, reloadingIntent),然后 initialLoadingIntent 可以在发出一次后完成,即使用Observable.just(true) ...我会将Observable.merge(...) 放入 Presenter 并让视图提供两个意图.我将它放入 Presenter 的原因是,否则 View 会进行一些计算(合并的东西),这会使视图的转储少一些。在 Presenter 中也有这个允许你用一个简单的 android 单元测试来测试它,否则你将不得不编写一个 Android Instrumentation 测试
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-08
      • 1970-01-01
      • 2013-08-03
      • 2019-07-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多