-
Notifications
You must be signed in to change notification settings - Fork 841
Open
Description
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 the ProductDetailsPresenter
and ProductDetailsActivity
to provide some test for me.
I add a testBtnIntent()
method for the ProductDetailsView
to handle a click intent.
public class ProductDetailsActivity extends MviActivity<ProductDetailsView, ProductDetailsPresenter>
implements ProductDetailsView {
@Override
public Observable<Boolean> testBtnIntent() {
return RxView.clicks(btnTest).share().map(it -> true);;
}
@Override public void render(ProductDetailsViewState state) {
Timber.d("render " + state);
if (state instanceof ProductDetailsViewState.LoadingState) {
renderLoading();
} else if (state instanceof ProductDetailsViewState.DataState) {
renderData((ProductDetailsViewState.DataState) state);
} else if (state instanceof ProductDetailsViewState.ErrorState) {
renderError();
} else if (state instanceof ProductDetailsViewState.TestViewState) {
TestClickActivity.start(this);
} else {
throw new IllegalStateException("Unknown state " + state);
}
}
}
And then mergeWith
the loadDetails
method
@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());
subscribeViewState(loadDetails.mergeWith(clickTest), ProductDetailsView::render);
}
Because the viewStateBehaviorSubject
will reemit the latest viewstate
, so it will always reemit the clickTest
when I go back the previous page and the TestClickActivity
will open again and again, The expected should be to go back to the previous page without reemit the click event. Sorry
for my bad English. hope I can explanation of this. And can you give me some suggestion?
tschuchortdev, andreiverdes, jamolkhon, szelk and heliam1
Activity
sockeqwe commentedon Jul 4, 2017
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
ProductDetailsActivity
is not changed by navigation per se, right?Navigation is "just" a side effect of a state change in ProductDetailsViewState. Side effects can be modeled in RxJava with
doOnNext()
operator.I think something like this should work:
Assuming you have some class
Navigator
:Then you could inject the
Navigator
intoProductDetailsPresenter
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?
[-]When merge the click event into the viewstateObservable [/-][+]Navigation in MVi[/+]littleGnAl commentedon Jul 5, 2017
@sockeqwe Thanks. It's a good solution, and maybe I can just pass the
View
to thePresenter
just likeMVP
does, but I think whether have a more elegant way to do this?(Maybe like your discussion in #255)andreiverdes commentedon Aug 29, 2017
Hi!
I chose to include navigation through the MVI pattern to be able to log every user action within the app.
I had the same problem above and couldn't just pass references to a
Navigator
or start activities from the Presenter because I keep the presentation layer in a separate project module.My solution was to clear the navigation flags with another MVI intent triggered by
onPause
.I know it's a bit dirty, I'm new to MVI, any feedback is welcomed! :D
PS: Great library!
abyrnes commentedon Feb 16, 2018
@sockeqwe How do you suggest handling navigation in the case where the next screen needs data that is in the view state?
skykelsey commentedon Apr 11, 2018
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?
abyrnes commentedon Apr 11, 2018
@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: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 outNoOp
view states, has yet to cause me any issues.sockeqwe commentedon Apr 11, 2018
tschuchortdev commentedon Apr 27, 2018
Any news on this? I couldn't find anything about it on your blog.
sockeqwe commentedon Apr 27, 2018
My bad, I haven't had time to write a blog post or clean up my example repository ... Maybe next week ... sorry ...
skykelsey commentedon May 1, 2018
Thanks @sockeqwe I'm interested as well when you find the time.
sockeqwe commentedon May 6, 2018
Here you go:
http://hannesdorfmann.com/android/mosby3-mvi-8
Hope someone find it helpful.