Say goodbye to all main thread problems in MVP

  2 mins read

Months ago I created a sample project demonstrating clean architecture in Android, you can see it here. One of the main problems when I created this project was the threading, in Android if you do too much work in the Ui thread you have drawing problems and your Ui can seem unresponsive while you keep the Ui thread busy, also you can’t touch any Ui component from any worker thread, this calls have to be in the Ui thread.

When I created this MVP project I faced that problem and I tried to abstract this threading problems into the delivery mechanism, Android in this case. The communication between View and a Presenter is in the same thread because the action that a Presenter does are usually little things and most times is only a call to domain and this is done in a worker thread.

The other problem was when an interactor (asynchronous call) has finished and I have to refresh the screen with some retrieved data in background, you need the Ui thread, but only when touching widgets, if you have to do some other actions it’s better to keep the worker thread alive and return to the main thread only when needed.

Ui_thread_worker

Keeping this on my mind I decided to decorate my View implementations with a Handler to post the results in the Ui Thread,
so my Presenter and my View interface are part of my java presentation module and using the view decorator the change to the UI thread is done seamlessly and transparently keeping the presenter decoupled from thread changing logic. Let’s see some code:

public class MainPresenter {
  private MainView mainView;

  public void attachiew(MainView mainView) {
    this.mainView = mainView;
  }

  public void doSomeViewAction() {
    interactorInvoker.execute(getContactsInteractor, new InteractorOutput<List<Contact>, ObtainContactsException>() {
      @Override public void onResult(List<Contact> result) {
        mainView.doSomeAction();
      }
...
    });
  }
}

This MainPresenter, executes with an InteractorInvoker (ThreadPoolExecutor abstraction) a thread to get some Contact result. When the interactor is completed it needs to call a method in the view, so it makes the call to the view without thinking about any threading problem and keeps the presenter absctract about threading issues.

public class DecoratedMainView implements MainView {
  private final MainView undecoratedView;
  private final ThreadSpec threadSpec;

  public DecoratedMainView(MainView undecoratedView, ThreadSpec threadSpec) {
    this.undecoratedView = undecoratedView;
    this.threadSpec = threadSpec;
  }

  @Override public void doSomeAction() {
    this.threadSpec.execute(new Runnable() {
      @Override public void run() {
        undecoratedView.doSomeAction();
      }
    });
  }
}

To do that, you have to call handler.post() or runOnUiThread() in order to change the thread in the view, but the code will become verbose and maybe I can forget in some circustances to implement that, so I created a code generator to let this implemented autommatically for you without any effort, the usage is pretty simple, you only have to annotate your view interface with @ThreadDecoratedView and when you need this decorated view call ViewInjector.inject(mainViewImpl, threadSpec); a ThreadSpec is just a simple interface that implements execute method, so in that implementation you can just use your Handler. Now the code becomes easier:

@ThreadDecoratedView public interface MainView {
  void doSomeAction();
}

public class MainViewImp implements MainView {
  public void onCreate() {
    mainPresenter.attachView(ViewInjector.inject(mainView, threadSpec));
  }

  @Override public void doSomeAction() {
    listview.notifyDataSetChanged();
  }
}

This implementation was in Clean Contacts but I decided to extract this functionality to a library and use it across other side projects, so I published a library called ViewThreadDecorator to Github.

Written by:

Christian Panadero Martinez

  • mzgreen

    And what about configuration changes? How does your solution behave if you rotate the device when a request to the server is running in the background? Is result still delivered? Is request restarted or it continues it’s work normally? Are you sure that there is no memory leaks? These are common problems that devs encounter when dealing with threading, that’s why I’m asking 🙂

    • Hi @mzgreen:disqus
      About config changes: It depends on the behaviour that you want to achieve. In my case I have a ThreadPoolExecutor that is singleton on my app so my Use case will continue running, and it will update the view when complete.
      About memory leaks, This Decorator pattern shouldn’t have any leaks cause you are providing the ThreadSpec and this threadspec should be managed by you, so the library is only decorating your View Interface.

      You can see this implementation working in my project on Github Clean-Contacts.

      Thanks for your comment!

  • Dmitry Zaytsev

    On a practical side of the question – how do you find the end result after moving presenter’s code out of the main thread? Is it faster now or is there no noticeable difference (which is also good by itself)?

    • Usually I communicate my presentation layer with my domain layer in other thread, is a good practice since the presenter is not responsible to know if you are going to hit the network, bdd or any external agencies, so I decide to leave the UI thread asap. This solution is to stop to worry about returning ui threading in your presentation layer.

      So, in summary, if you do heavy calculations is better to work in another thread, but I prefer to treat everithing in the same way and stop worry about threading, that is the change that matters.

  • Roman Temchenko

    Does it mean that decorator has to override each action of decorated view and duplicate threading code everywhere? Is there any way to have run-time generic proxy that would handle all interactions?

    • Yes, the decorator has to decorate every action that needs to touch the view. In order to keep it simple I created a library that does that for you (https://github.com/PaNaVTEC/ViewThreadDecorator).

      There is a way to create a runtime proxy using reflection, but it has 2 main cons imho:
      – It should be slower since is using reflection to interpret any call.

      – If you have a crash in the code, the stack trace will be messed up since the exception comes from the proxy.

      My first implementation was to use the proxy, but after a while I decided to create that library to use as much generate code as I could and avoid the usage of reflection on my projects.

      • Roman Temchenko

        I see. I am not familiar with Java. Looks like you have cool tools. Do you use anything similar for running interactors in background? I mean injecting interactorInvoker everywhere, and running invoker.execute… all the time is not great too. Do you hide this threading detail somehow?

        • I don’t have anything for that, I just inject the dependency into the constructor and use it directly. you can do something like `useCaseInvoker.invoke(useCase, callbacks)` which already abstracts the fact that this call is async.

          • Roman Temchenko

            I totally understand that. It is just the fact, that I was not sure if presenters should deal with threading at all. In my case presenters always operate on main thread. But it is not always convenient to do that in use cases. And I don’t want to proliferate threading in business logic. So I was confused where that threading should go at all. Thank you for answers.