📜 ⬆️ ⬇️

Moxy Strategies (Part 1)


Moxy framework developed by us with Yura is widely used in Android development. It provides the MVP implementation of the pattern when working with Activity, Fragment and View, completely separating the “callback hell” of their life cycle from the presenter.

This behavior is implemented by the ViewState entity, which proxies method calls between Presenter and View, while keeping some of them in the queue based on special strategies. When recreating a View, not all methods are called, but only those that are in the queue at the moment.

In this article, we will describe how the out-of-box strategies work, and when to use each of them. On the mechanism of the work of strategies from the inside and writing custom strategies, see Part 2 .

Moxy working principles
')
The queue of commands (methods that are called on the view) in the presenter define the View states after the re-creation.

The commands in the queue are saved according to the strategy specified for it in the method of the View interface. ViewState itself is generated at compile time based on the View interface and the annotations used in it.

Inaccurate use of strategies can lead to incorrect application behavior and memory overflow.

Commands can be applied to the View only when it is in the active state — in the interval between calls to the getMvpDelegate (). OnAttach () and getMvpDelegate (). OnDetach () methods from Activity , Fragment, or custom android.view.View .


Circuit device

To illustrate how strategies work, we will use the following scheme:


The X axis is the time scale (left-to-right time direction).

Circles indicate teams, identical teams (respectively, having the same strategy) are indicated by circles with the same color and number.

The axis of the presenter displays the commands that the presenter initiates using the getViewState (). DoSomething (args) method. The team performed by the presenter has the strategy that is considered in this scheme, unless otherwise indicated.

The ViewState axis is the state of a queue of commands that are applied to the View upon its subsequent re-creation. Commands are applied sequentially, from bottom to top. The initial state of the ViewState is displayed in the leftmost position on the axis.

The View axis is a set of commands that have been applied to the View. The orientation change icon means re-creating the View. The View axis can start from the middle of the diagram - this means that the View has moved to the active state from this very moment.

Out of box strategies

Moxy provides the following strategies by default:

AddToEndStrategy - execute the command and add the command to the end of the queue
AddToEndSingleStrategy - execute a command, add it to the end of the queue and delete all its previous instances
SingleStateStrategy - execute the command, clear the queue and add the command to it
SkipStrategy - execute the command
OneExecuteStrategy - execute the command as soon as possible

Let's take a closer look at how they work and when they should be applied.

AddToEndStrategy

AddToEndStrategy is the simplest strategy, which is to add a command to the end of the queue:


When calling a team presenter (2) with AddToEndStrategy strategy:


When recreating a View:


AddToEndSingleStrategy

This strategy differs from AddToEndStrategy in that there can be only one instance of each command in the ViewState queue marked with this strategy.

Extended use
When using custom commands, you can change the queue status (for example, duplicate any of the available commands), but this should be done with great care)



When calling a team presenter (2) with the AddToEndSingleStrategy strategy:


When recreating a View:


SingleStateStrategy

This strategy is similar in principle to AddToEndSingleStrategy. The difference is that when a command with this strategy is entered into the ViewState, the command queue is cleared completely.



When calling a team presenter (1) with the SingleStateStrategy strategy:


When recreating a View:


SkipStrategy

Skip strategy does not change the viewstate stack. The command is applied to the View, only if it is in the active state.



The team behaves differently, depending on the presence of a view in the active state.

a) If the View is in the active state:

When calling a team presenter (4) with the SkipStrategy strategy, if the View is in the active state:


When recreating a View:


b) In the absence of the View in the active state:

When calling a team presenter (4) with the SkipStrategy strategy, in the absence of the View in the active state:


When recreating a View:


OneExecuteStrategy

This strategy is very similar to SkipStrategy. The difference is that when there is no view in the active state, the command waits until it appears, and then it is applied exactly once.



The team behaves differently, depending on the presence of a view in the active state.

a) If the View is in the active state:

When a team calls a presenter (4) with the OneExecuteStrategy strategy, if the View is active (Behavior is completely the same as SkipStretegy):


When recreating a View:


b) In the absence of the View in the active state:

When calling a team presenter (4) with the OneExecuteStrategy strategy, in the absence of the View in the active state:


When View is active:



Lack of strategy for the method

The absence of an explicit indication of the strategy of the method leads to its automatic output based on the strategy for the entire interface and the default strategy. Currently, the default strategy is AddToEndStrategy.

Command scope

In this section, we have collected typical cases of the use of commands.

AddToEndStrategy - used when you need to consistently apply several commands that need to be reapplied when recreating a View.

Example: The organization screen consists of 3 blocks: general information, promotions, purchase history. These parts can be loaded and displayed on the screen asynchronously. After re-creating it is important to display information in all blocks. All methods will be marked with the strategy AddToEndStrategy

AddToEndSingleStrategy - used when the command is to be used when recreating a view no more than once.

Example: There is a loading indicator on the screen, the visibility of which is changed by calling the View method: toggleLoading (visible: Boolean).

Spoiler: here and hereafter code examples are shown on Kotlin.
This method will have an AddToEndSingleStrategy strategy.

SingleStrategy - applies if we don’t care about the result of commands that worked before it.

Example: Profile screen data is downloaded from the network. The screen has 3 mutually exclusive states: loading, data display and screen — stub. Accordingly View has methods showLoading (), showData () and showStub (). All three teams will have the strategy SingleStateStrategy.

SkipStrategy - used in case we need to perform some action right now and only in case there is a View in the active state.

Example 1: There is a screen for editing user data. When you click the save button, the load indicator is displayed by calling the toggleLoading command (show = true). If the load fails, the screen returns to its original state with the command toggleLoading (show = false) and the SnackBar is displayed with the error information with the command showLoadingError (). The last team will have a SkipStrategy strategy, since the result of its execution is needed only with the active screen and should not be saved when changing the configuration.

Example 2: Starting an animation after some user action. It makes sense to use the command only once, and in the absence of an active view you do not need to save it to a queue.

OneExecuteStrategy - used if we need to perform some action when the View first appears in the active state.

Example 1: Opens the next screen. Launching a new Activity, Fragment, or FragmentDialog is conveniently performed through this strategy. In this case, we will have guaranteed 1 launch.

Refinement
To be more precise, guaranteed launch at the first Attachment View. If for some reason View was not in the active state and it did not come to the active state, the command will not be invoked. This situation is theoretically possible, you need to keep this in mind.

OneExecuteStrategy and SkipStrategy are very similar, be careful when using them.

How to avoid problems due to strategies?

When using strategies, you may encounter two kinds of problems:

Problem 1. Unnecessary teams in the queue

When using only AddToEndStrategy, which is the default strategy, the queue is gradually increasing. This may cause:


Decision:

Try to minimize the size of the command queue by setting strategies.

Problem 2. Wrong state during re-creation view

Often, an application requires only portrait orientation, as a result of which it is fixed during development, however, the re-creation of the view takes place not only when the orientation changes, but also during other configuration changes.

Decision:

When developing leave the possibility of changing the orientation of the application. This will help you to control not only the correct application of strategies, but also the other side effects of changing the configuration of the device.

Conclusion

Moxy strategies are a fairly flexible tool, the careless use of which can lead to logical errors. We hope this article will make using Moxy more transparent and obvious.

In Part 2, we consider the mechanism of how strategies work from the inside and how to create custom strategies.

Let your code always execute as you designed it!

from the authors of the Moxy Xanderblinov and senneco library

Materials on the topic


Source: https://habr.com/ru/post/325816/


All Articles