Skip to content

Commit

Permalink
typo
Browse files Browse the repository at this point in the history
  • Loading branch information
sockeqwe committed Jan 11, 2017
1 parent d07f607 commit 2e9f0ed
Showing 1 changed file with 7 additions and 7 deletions.
14 changes: 7 additions & 7 deletions _posts/2017-01-09-mosby3-mvi-1.md
Expand Up @@ -93,7 +93,7 @@ Let's discuss this points and let's see how "traditional" implementations of MVP

## 1. The State Problem
Reactive Apps - this is a buzzword, isn't it? With that I mean apps with a UI that react on state changes. Ah, here we have another nice word: "State". What is "State"? Well, most of the time we describe "State" as what we see on the screen like "loading state" when the View displays a ProgressBar. Therein lies the crux: we frontend developers tend to be focused on UI. That is not necessarily a bad thing because at the end of the day a good UI decides whether or not a User will use our app and therefore how successful an app is. But take a look at the very basic MVP code example from above (not the one using PersonsModel).
Here the state of the UI is coordinated by the Presenter. The Presenter tells the view what to display. The presenter drives the state of the UI. The same is true for MVVM. In this blog post I want to distinguish between two MVVM implementations: The first one with android's data binding and the second option using RxJava. In MVVM with data binding the state directly sits in the ViewModel:
Here the state of the UI is coordinated by the Presenter since the Presenter tells the View what to display. The Presenter drives the state of the UI. The same is true for MVVM. In this blog post I want to distinguish between two MVVM implementations: The first one with android's data binding and the second option using RxJava. In MVVM with data binding the state directly sits in the ViewModel:

{% highlight java %}
class PersonsViewModel {
Expand All @@ -119,7 +119,7 @@ class PersonsViewModel {
}
{% endhighlight %}

In MVVM with RxJava we don't use the data binding engine but bind Observable to UI Widgets in the view, for example:
In MVVM with RxJava we don't use the data binding engine but bind Observable to UI Widgets in the View, for example:

{% highlight java %}
class RxPersonsViewModel {
Expand Down Expand Up @@ -157,7 +157,7 @@ Of course this code snippets are not perfect and your implementation may look en
This leads to the following observations:

1. The business logic has his own state, the Presenter (or ViewModel) has his own state (and you try to sync the state of business logic and Presenter so that both have the same state) and the View may also has his own state (i.e. you set the visibility somehow directly in the View or android itself restores the state from bundle during recreation).
2. A Presenter (or ViewModel) has arbitrary many inputs (the view triggers an action handled by Presenter) which is ok, but Presenter have many outputs (or output channels like view.showLoading() or view.showError() in MVP or ViewModel is offering multiple Observables) which eventually leads to conflicting states of view, presenter and business logic especially when working with multiple threads.
2. A Presenter (or ViewModel) has arbitrary many inputs (the View triggers an action handled by Presenter) which is ok, but Presenter have many outputs (or output channels like view.showLoading() or view.showError() in MVP or ViewModel is offering multiple Observables) which eventually leads to conflicting states of View, Presenter and business logic especially when working with multiple threads.

In best case this just results in visual bugs such as displaying a loading indicator ("loading state") and error indicator ("error state") at the same time like this:

Expand All @@ -167,7 +167,7 @@ This leads to the following observations:

In worst case, you have a serious bug reported to you from a crash reporting tool like Crashlytics that you are not able to reproduce and therefore fixing this issue is almost impossible.

What if we only have one single source of truth for state passed from bottom (business logic) to the top (the view). Actually, we have already showcased a similar concept at the very beginning of this blog post when we talked about "Model".
What if we only have one single source of truth for state passed from bottom (business logic) to the top (the View). Actually, we have already showcased a similar concept at the very beginning of this blog post when we talked about "Model".

{% highlight java %}
class PersonsModel {
Expand All @@ -190,8 +190,8 @@ Guess what? **Model reflects the State**. Once I have understood this, a lot of
Understanding what a "Model" is and how to model it properly at the end solves the "State Problem"

## 2. Screen orientation changes
In android screen orientation changes is a challenging problem. The simplest way to deal with that is to ignore it. Just reload everything on each screen orientation change. This is a completely valid solution. Most of the time your app works offline too so that data comes from database or another local cache. Therefore that loading data is super fast after screen orientation changes. However, I personally, dislike to see a loading indicator even if it's just for a few milliseconds because in my opinion this is not a seamless user experience. So people (including myself) started to use MVP with "retaining presenter" so that a view can be detached (and destroyed) during screen orientation changes whereas the Presenter survives in memory and then the View gets reattached.
The same concept is possible with MVVM with RxJava but you have to keep in mind that once a view gets unsubscribed from his ViewModel the observable stream is destroyed. You could work around this with Subjects for example. In MVVM with data binding your ViewModel is directly bound to the View by the data binding engine himself. To avoid memory leaks, you have to destroy the ViewModel on screen orientation changes.
In android screen orientation changes is a challenging problem. The simplest way to deal with that is to ignore it. Just reload everything on each screen orientation change. This is a completely valid solution. Most of the time your app works offline too so that data comes from database or another local cache. Therefore that loading data is super fast after screen orientation changes. However, I personally, dislike to see a loading indicator even if it's just for a few milliseconds because in my opinion this is not a seamless user experience. So people (including myself) started to use MVP with "retaining presenter" so that a View can be detached (and destroyed) during screen orientation changes whereas the Presenter survives in memory and then the View gets reattached.
The same concept is possible with MVVM with RxJava but you have to keep in mind that once a View gets unsubscribed from his ViewModel the observable stream is destroyed. You could work around this with Subjects for example. In MVVM with data binding your ViewModel is directly bound to the View by the data binding engine himself. To avoid memory leaks, you have to destroy the ViewModel on screen orientation changes.

But the problem with retaining Presenter (or ViewModel) is: how do we bring the View's state back to the same state as it was before the screen orientation change so that both, View and Presenter, are in the same state again? I have written a MVP library called [Mosby](https://github.com/sockeqwe/mosby) with a feature called ViewState which basically synchronizes the state of your business logic with the View. [Moxy](https://github.com/Arello-Mobile/Moxy), another MVP library, implemented a quite interesting solution by using "commands" to reproduce the View's state after a screen orientation change:

Expand All @@ -205,7 +205,7 @@ So, again, having one "Model" which reflects the current "State" and exactly one

## 3. Navigation on the back stack
Does a Presenter (or ViewModel) needs to be kept when the View is not in use anymore? For instance if the Fragment (View) has been replaced with another Fragment because the user has navigated to another screen, there is no View attached to the Presenter. If no View is attached obviously a Presenter can't update the View with the latest data from business logic. What if the user comes back (i.e. pressing the back button to pop the back stack)? Reload the data? This is more a philosophical question.
Usually once the user comes back to a previous screen on the backstack he would expect to continue where he left off. This is basically the "restore View's state problem" as discussed in 2. So the solution is straight forward: With a "Model" representing the state we just call _getView().render(PersonsModel)_ to render the view when coming back from back stack.
Usually once the user comes back to a previous screen on the backstack he would expect to continue where he left off. This is basically the "restore View's state problem" as discussed in 2. So the solution is straight forward: With a "Model" representing the state we just call _getView().render(PersonsModel)_ to render the View when coming back from back stack.

## 4. Process death
I think it is a common misunderstanding in android development that process death is a bad thing and that we need libraries that help us to restore state (and Presenters or ViewModels) after process death. First, a process death only ever happens for a good reason: the android operating system needs more resources for other apps or to save battery. But this will never happens when your app is foreground and actively used by your app's user. So be a good citizen and don't fight against the platform. If you really have some long running work to do in the background use a _Service_ as this is the only way to signal the operating system that your app is still "actively used".
Expand Down

0 comments on commit 2e9f0ed

Please sign in to comment.