2017-02-20 9 views
2

私は新しいデモアプリケーションに新しいMosby MVIライブラリを使用しています。 プレゼンターでインテントを定義するときに、ビューがアタッチされたときにインテントがトリガーされたり放出されたりすると、インテントが不一致になります。例えばMosby MVI:意図しないインテントバインディングの動作

:この意図は正常に動作します

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

:さんは次のように発表者が意図的に結合する

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

活動に非常に単純な意図を定義してみましょう。別のアクティビティ(詳細ビュー)にナビゲートして戻ると、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); 
} 

はありません。インテントは、ビューが再接続されたときに新しい項目を送出します。私の場合は、最後のViewStateを再利用するのではなく、データをリロードするためのバックエンドへの新しいAPU呼び出しが行われます。これは、reloadData()が呼び出されない場合でも発生します。

この動作は非常に矛盾しています。ビューを再アタッチしているときにインテントがトリガーされたとき、どうすればコントロールできるのでしょうか?

更新:私にとって はさらに興味深いのは、再接続時に、私が観察を完了せず、意図の自動発光を避けるないか、です。 PublishSubjectの導入により、アクティビティは回転しているだけでもデータ全体をリロードします。

答えて

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) `です。この例では、1回転ごとにデータが完全にリロードされています。

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

Mosby MVIはリアクティブストリーム契約を尊重します。 intentLoadData()

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

Observable.just(true)を見てみないだけonNext(true)を呼び出すだけでなく、onCompleted()を呼び出します。リアクティブ・ストリームが完了すると、そのストリームを介してそれ以上のアイテムを放出することはできません。 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; 
    } 

} 

を。ライフサイクルイベントのためにObservableストリームを提供するTrelloのNaviのようなライブラリを使用することもできますが、アクティビティが破棄された場合(つまり画面の向きが変更されている場合)NaviがonCompleted()イベントを発行するので、同じ状況になります。後で再度インテントを実行する場合は、onCompleted()が呼び出されないようにしてください。

+0

私の問題は逆です。 PublishSubjectを使用すると、後でインテントをトリガするのに役立ちますが、ビューを再接続するときに 'bindIntents()'でインテントが出ないようにするにはどうすればよいですか? – TobiasRe

+0

「ビューを再接続する」とはどういう意味ですか?私に具体的な例を教えてもらえますか? – sockeqwe

+0

私は元の質問のようにWebサービスからデータを読み込むためにPublishSubject定義を使用します。アクティビティが開始され、データがロードされます。 デバイスを回転させると、MviBasePresenterの 'bindIntentActually()'の実行中に再度ロードインテントがトリガされます。私はこの不必要な再読み込みを避けたいです。 この場合、 'viewAttachedFirstTime'setをfalseにして' attachIntentActually() 'を' attachView() 'で呼び出します。それは私が再接続を指している理由です。 – TobiasRe

関連する問題