5 Good Reasons for Switching to Mortar

Jingsi Lu
Samsao
Published in
5 min readOct 23, 2015

After working on two projects with Mortar/Flow and later Mortar-Architect and refactoring an old project from traditional Activity/Fragment structure into it, it is time for me to give back to the Android community.

The learning curve is steep, but it is a good investment and the rewards are big. So, here are five reasons to be using Mortar:

  • No bugs due to Activity/Fragment lifecycles
  • Good decoupling
  • Modular architecture
  • Flexible navigation
  • Minimum boilerplate code

1. No bugs due to Activity/Fragment lifecycles

As most of us may know, using Fragments could be very painful in Android development. The lifecycle of Fragments is complex and it is hard for coders to debug due to its complexity. However, Mortar lets you use only one Activity with no fragments. It works with pure custom views. After setting up Mortar scopes in your app, your development does not need to deal with fragments anymore.

2. Good decoupling

The traditional Activity/Fragment architecture does not have a clear decoupling of view and controller. However, with Mortar, we can use the MVP design pattern which provides clean architecture and great decoupling. Each View has an associated Presenter. This Presenter works as a UI business logic provider that is isolated from View concerns. In this way, the View only presents the final UI to the users and is loosely coupled to the model.

3. Modular Architecture

Mortar serves as a delegate to system services, and everything is managed by MortarScope singletons. For instance, this mechanism makes your app’s dependencies, such as API clients and database helpers as well as business managers customly scoped. In short, these helpers and managers are alive as long as the custom scope is not destroyed. Therefore, in your app, you can get the dependencies’ instances in a presenter as long as the presenter exists in its scope. The Presenter’s lifecycle is as follows:

  • protected void onEnterScope(MortarScope scope)
  • protected void onLoad(Bundle savedInstanceState)
  • protected void onSave(Bundle outState)
  • public void dropView(View view)
  • protected void onExitScope()

Specifically, onEnterScope is called when the scope is created and added to the hierarchy; onLoad is called everytime a new view is created and attached to the presenter; onSave is called before the only activity/your app is killed by the system; dropView is called when a view is destroyed and unattached from the presenter; onExitScope is called when the scope is destroyed.

It is worth mentioning here that a presenter will never be destroyed in screen rotation, only its attached view will be destroyed. Therefore, your app will definitely survive configuration change. Compared with the pain of dealing with configuration change using fragments, this is really awesome!

The presenters can still be destroyed if your app is killed by android. But no worries, Mortar exposes a BundleService that allows the ViewPresenters to access to the Activity lifecycle’s persistence. When you start your app next time, the saved data could be retrieved from Bundle.

Square also developed a navigation system (Flow) for a better use of Mortar. Flow makes your app navigate forward and backward among different functional sections. Each of these sections is called a Screen (View + Presenter). However, I only had two choices when I worked with Flow, i.e. flow.set(new MainScreen()) and flow.goBack(). Also, the backstack managed by Flow does not keep previous scopes, which sucks. Because of this, I could not find a way to show a new dialog on top of the current view while the background view is still visible. Fortunately, Lukasz Piliszczuk works as a freelancer at Samsao, and he develops Mortar-Architect. Mortar-Architect implements the Model-View-Presenter (MVP) pattern with Mortar and provides a proficient view stack management alternative to Flow.

Architect Navigator class allows your app to navigate between Mortar scopes. It maintains a history stack that preserves previous Mortar scopes with their presenters. There are six navigations at your choice.

  • Navigator.push()
  • Navigator.show()
  • Navigator.replace()
  • Navigator.back()
  • Navigator.chain()
  • Navigator.set()

Navigator.push() will perform the view transition from the current view to a new view. After this transition, the current view will be destroyed and removed, but its scope and presenter are kept in the stack. Navigator.show() could be very useful when you want to show a dialog (not taking the whole screen) on top of the current screen. In this case, the current view is not destroyed and both views will be visible. For the other navigations and the key difference between Flow and Architect, please see the full description on the Github repository.

5. Minimum boilerplate code

Most of the critics on Mortar/Flow goes to the boilerplate code. Flow requires a lot of boilerplate code to make basic navigation work or even create Screen/Presenter/View. One of Mortar-Architect’s goal is to reduce the boilerplate code to a minimum. Mortar-Architect successfully achieves this by using code generation everywhere as possible.

a. Dependency Injection

Mortar-Architect works with Dagger2 for Dependency Injection. It provides Auto-Dagger2, an annotation processor, to generate your components. What you need to do is only annotating your class with @AutoComponent with dependencies, modules and superinterfaces; adding injector methods into a generated component, use @AutoInjector annotation; and to expose a dependency within a generated component, user @AutoExpose. A detailed example is provided below.

b. Mortar Scope

In order to scope your components and navigate between Mortar scopes, you will need to configure your Mortar scope, get the presenter ready, put Dagger2 component in your presenter and decide which View to display. With Mortar-Architect, you can annotate your class with @AutoStackable with two attributes: component and pathWithView. Then you are all set.

So, here is a brief example:

  • For your Presenter class:
@AutoStackable(
component = @AutoComponent(dependencies = RootActivity.class),
pathWithView = MainView.class
)
@DaggerScope(MainPresenter.class)
public class MainPresenter extends ViewPresenter<MainView> {}
  • For your View class:
@AutoInjector(MainPresenter.class)
public class MainView extends PresentedLinearLayout<MainPresenter>{}

Working with Mortar will have your app development less buggy, and help you test seamlessly since Mortar relies heavily on Dagger 2. On top of that, working with Mortar-Architect will let your development a lot easier and faster. It provides easy persistence mechanism for ViewPresenter in navigation history and an easy way to implement multiple transitions between screens. Along with all the other benefits, you will have more control on your app and your development will become more consistent. However, an area of improvement I find about Mortar-Architect is that if your errors occur before the codes are generated, you will have a huge load of errors, which makes you hard to locate the real errors.

Coming soon to Mortar-Architect: version 1.0 with new changes! I hope Mortar-Architect will gain more focus and help improve your app development!

--

--