Strategies in Moxy (Part 1)

  • Tutorial

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

This behavior is implemented due to the ViewState entity, which proxies method calls between Presenter and View, while storing some of them in the queue based on special strategies. When you recreate the View, not all methods are called, but only those that are currently in the queue.

In this article, we will describe how the strategies provided “out of the box” work, and in which cases each of them should be applied. Read about the mechanism of working strategies from within and writing custom strategies in Part 2.

Moxy working principles

The command queue (methods that are called on the view) in the presenter determines the state of the View after it is recreated.

Saving commands in the queue occurs according to the strategy specified for it in the View interface method. The 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 View only when it is in the active state - in the interval between calls to getMvpDelegate (). OnAttach () and getMvpDelegate (). OnDetach () from Activity , Fragmentor custom android.view.View .


Arrangement of the scheme

To illustrate the operation of the strategies, we will use the following scheme:


The X axis represents the timeline (time direction from left to right).

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

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

The ViewState axis represents the state of the command queue that applies to the View when it is subsequently recreated. Commands are applied sequentially, from lower to upper. The initial state of the ViewState is displayed in the leftmost position on the axis.

The View axis is the set of commands that apply to the View. An orientation change icon means recreating the View. The View axis can start from the middle of the diagram - this means that the View has entered the active state from this moment.

Strategies out of the box

Moxy provides the following strategies by default:

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

Consider in more detail how they work and when to use them.

AddToEndStrategy

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


When the presenter calls a command (2) with the AddToEndStrategy strategy:

  • Command (2) is added to the end of the ViewState queue.
  • Command (2) applies to the View, if it is in the active state

When you recreate the View:

  • ViewState commands are sequentially applied to View

AddToEndSingleStrategy

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

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



When the presenter calls command (2) with the AddToEndSingleStrategy strategy:

  • Command (2) is added to the end of the ViewState queue.
  • If the command (2) was already in the queue, the old command is removed from the queue
  • Command (2) applies to the View, if it is in the active state

When you recreate the View:

  • ViewState commands are sequentially applied to View

SingleStateStrategy

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



When the presenter calls the command (1) with the SingleStateStrategy strategy:

  • The command queue is completely cleared
  • Command (1) is added to the end of the ViewState queue.
  • Command (1) applies to the View, if it is in the active state

When you recreate the View:

  • ViewState commands are sequentially applied to View

SkipStrategy

Skip strategy does not change the ViewState stack. The command applies to View only if it is in an active state.



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

a) In the case of the presence of View in the active state:

When calling presenter commands (4) with SkipStrategy strategy, in the case of the presence of View in the active state:

  • The command applies to View
  • The team lineup remains unchanged.

When you recreate the View:

  • ViewState commands are sequentially applied to View

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

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

  • The command does not apply to View
  • The team lineup remains unchanged.

When you recreate the View:

  • ViewState commands are sequentially applied to View

OneExecuteStrategy

This strategy is very similar to SkipStrategy. The difference is that in the absence of view in the active state, the command waits for its appearance, and then applies exactly once.



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

a) In the case of the presence of View in the active state:

When calling presenter commands (4) with OneExecuteStrategy strategy, in the case of the presence of View in the active state (completely analogous manners SkipStretegy):

  • The command applies to View
  • The team lineup remains unchanged.

When you recreate the View:

  • ViewState commands are sequentially applied to View

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

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

  • Command (4) is added to the end of the ViewState queue.

When View appears in an active state:

  • ViewState commands are sequentially applied to View

  • When command (4) is executed, it is removed from the command queue. Subsequent recreation of the View command (4) will not be called.

The absence of a strategy for a method

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

Scope of commands

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

AddToEndStrategy - used when you need to apply several commands sequentially, which must be reapplied when you recreate the View.

Example: Organization screen consists of 3 blocks: general information, promotions, purchase history. These parts can be downloaded and displayed on the screen asynchronously. After reconstituting, it is important to display information in all blocks. All methods will be marked strategy AddToEndStrategy

AddToEndSingleStrategy - used when the command should be used when recreating view more than once.

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

Spoiler: hereinafter code examples are given on Kotlin.
This method will have the AddToEndSingleStrategy strategy.

SingleStrategy - used if the result of the teams that worked before it is not important to us.

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

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

Example 1: There is a screen for editing user data. When you click save, the download indicator is displayed by calling the toggleLoading (show = true) command. If the download fails, the screen returns to the initial state with the toggleLoading command (show = false) and a SnackBar is displayed with the error information with the showLoadingError () command. The last team will have a SkipStrategy strategy, as 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 it is not required to save it in the queue.

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

Example 1: Opening the next screen. The launch of a new Activity, Fragment or FragmentDialog is conveniently performed using this strategy. In this case, we will have a guaranteed 1 launch.

Clarification
To be more precise, guaranteed launch at the first attachment View. If for some reason the View was not in the active state and did not come into the active state, then the command will not be called. 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 types of problems:

Problem 1. Extra commands in the queue

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

  • Freeze ui when attaching View to Presenter
  • Memory overflow

Solution:

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

Problem 2. Improper state when reconstructing view.

Often an application requires only portrait orientation, as a result of which it is fixed during development, however, reconstructing a view occurs not only when the orientation is changed, but also during other configuration changes.

Solution:

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

Conclusion

Strategies in Moxy are a fairly flexible tool, the inaccurate use of which can lead to logical errors. We hope that this article will make the use of Moxy more transparent and obvious.

In part 2, we will examine the mechanism by which strategies work from the inside out and how to create custom strategies.

Let your code always execute the way you designed it!

from the authors of the library Moxy Xanderblinov and senneco

Related Materials



Also popular now: