-
Notifications
You must be signed in to change notification settings - Fork 841
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Navigation in MVi #261
Comments
We have some similar discussion about SnackBar here #255 However, I think navigation can be seen as "side effect" since it is not affecting (nor changing) the state for your current View. For Example the state of Navigation is "just" a side effect of a state change in ProductDetailsViewState. Side effects can be modeled in RxJava with I think something like this should work: class Navigator {
private final Activity activity;
@Inject
public Navigator(Activity activity){
this.activity = activity;
}
public void navigateToTestActivity(){
TestClickActivity.start(activity);
}
} Then you could inject the class ProductDetailsPresenter extends MviBasePresenter<...> {
private final Navigator navigator;
@Inject
public ProductDetailsPresenter(Navigator navigator){
this.navigator = navigator;
}
@Override protected void bindIntents() {
...
Observable<ProductDetailsViewState> loadDetails =
intent(ProductDetailsView::loadDetailsIntent)
.doOnNext(productId -> Timber.d("intent: load details for product id = %s", productId))
.flatMap(interactor::getDetails)
.observeOn(AndroidSchedulers.mainThread());
Observable<ProductDetailsViewState> clickTest =
intent(ProductDetailsView::testBtnIntent)
.map((aBoolean) -> new ProductDetailsViewState.TestViewState())
.doOnNext( aBoolean -> navigator.navigateToTestActivity() ); // Navigation as side effect
subscribeViewState(loadDetails.mergeWith(clickTest), ProductDetailsView::render);
}
} Of course you have to keep in mind that Navigator might leak the Activity on config change (since presenter is kept during config change). I just wanted to illustrate a possible solution. Does this makes sense? |
Hi! Presenter.kt
...
override fun bindIntents() {
...
val clearViewStateIntent = intent { view -> view.clearNavigationIntent()}
.map { LandingViewState() }
.subscribeOn(Schedulers.io())
val allIntents = Observable.merge(
createViewIntent,
loginIntent,
signUpIntent,
clearViewStateIntent
).observeOn(AndroidSchedulers.mainThread())
subscribeViewState(allIntents, LandingContract.View::render)
} Activity.kt
...
override fun onPause() {
pauseSubject.onNext(true)
super.onPause()
}
override fun render(viewState: LandingContract.State) {
when (true) {
viewState.navigateToLoginScreen() -> SignInActivity.start(this)
viewState.navigateToManageScreen() -> ManageActivity.start(this)
viewState.navigateToSignUpScreen() -> SignUpActivity.start(this)
}
}
override fun clearNavigationIntent(): Observable<LandingContract.Intent.ClearNavigationIntent> {
return pauseSubject.map { LandingContract.Intent.ClearNavigationIntent() }
} |
@sockeqwe How do you suggest handling navigation in the case where the next screen needs data that is in the view state? |
I'm having the same problem. It seems the problem is caused by using view state to accomplish navigation as a side effect, as @sockeqwe mentioned. I am not a big fan of passing the Activity into the Presenter though, so I will try out the approach @andreiverdes outlined. Would it be feasible to allow certain View States to be consumed instead of replacing the previous one? |
@skykelsey For this I've been having a dummy state that gets emitted by navigation intents (I call it val intent1 = intent(...)
val intent2 = intent(...)
val viewStateObservable = Observable.merge(intent1, intent1).filter { it !is NoOp }
subscribeViewState(viewStateObservable, View::render) This, however, doesn't solve the main problem at hand, for which I still haven't come up with an elegant solution, unfortunately. It doesn't seem like Mosby is well equipped to handle navigation in the presentation layer. So in the meantime I've implemented a base presenter that inherits from |
Jfyi: I have figured out a simple pattern of how to do navigation properly
(not only MVI related, but works well with MVI).
I can share it next week as I'm going to present it on a Meetup next Monday.
Stay tuned.
Andy Byrnes <[email protected]> schrieb am Mi., 11. Apr. 2018, 06:22:
… Would it be feasible to allow certain View States to be consumed instead
of replacing the previous one?
@skykelsey <https://github.com/skykelsey> For this I've been having a
dummy state that gets emitted by navigation intents (I call it NoOp) and
is just filtered out to avoid any unnecessary renderings:
val intent1 = intent(...)val intent2 = intent(...)
val viewStateObservable = Observable.merge(intent1, intent1).filter { it !is NoOp }
subscribeViewState(viewStateObservable, View::render)
This, however, doesn't solve the main problem at hand, for which I still
haven't come up with an elegant solution, unfortunately. It doesn't seem
like Mosby is well equipped to handle navigation in the presentation layer.
So in the meantime I've implemented a base presenter that inherits from
MviPresenter and hacks away at its implementation details to retrieve the
previous view state, if it exists, and directly notify the view that a
navigation event has occurred. This, combined with filtering out NoOp
view states, has yet to cause me any issues.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#261 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAjnrgjDcIoSd1TIj7nYK38vlE5ctmrdks5tnYUegaJpZM4ONlOH>
.
|
Any news on this? I couldn't find anything about it on your blog. |
My bad, I haven't had time to write a blog post or clean up my example repository ... Maybe next week ... sorry ... |
Thanks @sockeqwe I'm interested as well when you find the time. |
Here you go: Hope someone find it helpful. |
Consider such a demand:Click the button to post data to the server and then navigate to the other
Activity
when request success. I modified theProductDetailsPresenter
andProductDetailsActivity
to provide some test for me.I add a
testBtnIntent()
method for theProductDetailsView
to handle a click intent.And then
mergeWith
theloadDetails
methodBecause the
viewStateBehaviorSubject
will reemit the latestviewstate
, so it will always reemit theclickTest
when I go back the previous page and theTestClickActivity
will open again and again, The expected should be to go back to the previous page without reemit the click event. Sorryfor my bad English. hope I can explanation of this. And can you give me some suggestion?
The text was updated successfully, but these errors were encountered: