The premise

This article focuses on how our MVP CLEAN relates to the PRESENTER layer architecture, and how to highly reuse the PRESENTER we have already written, thus reducing a lot of code. Writing this article is also my own thoughts. Those interested can check out the two links on Clean and MVP architectures. (If there are errors or structural problems in the article, please correct them.)

  • CleanArchitecture
  • android-architecture

The purpose of this article is simple: how to implement presenter reuse with a highly abstract interface. It mainly solves how to reuse presenters already written in multiple data requests in UI pages.

motivation

Let’s start by talking about whether, when I was building the MVP framework, I should write a presenter model for every data operation on a page. You can also write a Contract to connect a View to a presenter. That would be the MVP effect.

  1. A single data request for a single page might save a lot of code
  2. For multiple data operations on a single page, our Presenter can become bloated.
  3. And these pages (single page single data request, single page multiple data request) will have many of the same data operation content. It doesn’t get reused

This article addresses that question

See the chart

architecture.png

I hope you don’t mind. Ok, let’s start with this picture.

I’m going to briefly describe the structure of this graph, because every API (whether it’s a network request or a database operation) is useful, So we can abstract each data operation into a Presenter and a View and for single-data operations we can call preseter and for multi-data operations we can use a powerPresenter to complete the request to that page.

The single data operation has little to show for it, but how the multi-data operation performs the callback of the View layer interface and the corresponding event callback. To complete this powerPresenter

The completion of the base

Everyone may write base differently, depending on the business to encapsulate the base, if we want to achieve a high degree of reuse of the base, our View layer of the base of the Base of the Presenter layer of the base of the Act layer are all related. Finally, what we want to do, without further ado, is get to the code.

  • View Layer
    public interface BaseView {

    void showLoading();

    void hideLoading();

    void showError(String message);

}Copy the code

There’s nothing there that encapsulates the basic business itself.

  • Presenter Layer
public interface Presenter<T extends BaseView> {

    void destroy();

    void attachView(T view);

    void detachView();

}Copy the code

The main function of this layer, which can also be seen from the interface, is to bind the corresponding View and unbind to prevent memory leaks (similar to most packaged interfaces). Presenter is not so simple and we re-wrap this layer again

public abstract class WrapperPresenter<T extends BaseView> implements Presenter<T> {

    T mView;

    @Override
    public void attachView(T view) {
        mView = view;
    }

    @Override
    public void detachView() { mView = null; }}Copy the code

The purpose of this wrapper is simply to eliminate the need to pass in a view every time you write a presenter and get it directly from the Activity.

  • Activity
public abstract class BaseMvpAct<T extends WrapperPresenter> extends AutoLayoutActivity implements BaseView {
    protected T mPresenter;
    private Unbinder bind;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(addContentView());
        bind = ButterKnife.bind(this);
        mPresenter = createP();
        if(mPresenter ! = null) { mPresenter.attachView(this); } initialize(); } public abstract void initialize(); public abstract T createP(); public abstract int addContentView(); @Override protected voidonDestroy() {
        super.onDestroy();
        if(mPresenter ! = null) { mPresenter.detachView(); }if (bind! = null) { bind.unbind(); }}}Copy the code

This is the base class of BaseAct, and you can see from generics that to base this Act we need to pass a subclass of WrapperPresenter. We just saw the view binding in WrapperPresenter, which we did in Base, so we don’t need to pass the View as an argument when implementing an API’s presenter.

Implementation of subclasses

Said so much, did not see reuse ah, hot chicken, oh boy don’t worry, take your time.

With these bases, we can show the real technology. After writing these bases, we can start to crazily strip the code to complete the Presneter and corresponding View of every data operation. To create a Presenter and View, you can use !!!! Comes to

view
public interface BannerView extends BaseView {
    void render(BannerBean bean);
}Copy the code
presenter
Public class BannerPresenter extends WrapperPresenter<BannerView> {private BannerTask extends WrapperPresenter<BannerView>; publicBannerPresenter() {
        task  = new BannerTask(new ApiIml(),new UIThread());
    }

    public void initialize(String type){
        mView.showLoading();
        this.getBanner(type);
    }

    public void getBanner(String type) {/ / perform network request callback to the Observer then back through the view in the parent class participation task. Execute (new BannerObserver (), BannerTask. Params. ForType (type));
    }

    private void BannerShow(BannerBean bean){
        mView.render(bean);
    }

    private void BannerLoadFailed(Throwable ex){
        mView.showError(ex.getMessage());
    }

    @Override
    public void destroy() { task.dispose(); } private final class BannerObserver extends DefaultObserver<BannerBean>{ @Override public void onNext(BannerBean BannerBean) {/ / back to view BannerPresenter refs. Enclosing BannerShow (bannerBean); } @Override public voidonComplete() { mView.hideLoading(); } @Override public void onError(Throwable exception) { BannerPresenter.this.BannerLoadFailed(exception); mView.showError(exception.getMessage()); }}}Copy the code

The code above has been commented so we don’t have to talk too much about it. It doesn’t matter that much about that task is the encapsulation of a network request.

Act
public class BannerAct extends BaseMvpAct<BannerPresenter> implements BannerView {
    @Override
    public void showLoading() {

    }

    @Override
    public void hideLoading() {

    }

    @Override
    public void showError(String message) {
        Log.i("cuieney"."showError: ");
    }

    @Override
    public void render(BannerBean bean) {
        Log.i("cuieney"."render: "+bean.toString());
    }

    @Override
    public void initialize() {
        mPresenter.initialize("banner");
    }

    @Override
    public BannerPresenter createP() {
        return new BannerPresenter();
    }

    @Override
    public int addContentView() {
        return0; }}Copy the code

The code is very simple, see all understand, complete the left half of the single page single data request.

Emphasis (single page multiple data request)

Back to the topic, how to reuse presenters for single page multiple data requests without having to write redundant presenters.

As you can see from the above figure, our input gives something to the presenter (which data operations are required), and PowerPresenter Output returns the corresponding data operations. Not so much code

public class PowerPresenter <T extends BaseView> extends WrapperPresenter<T>{
    private T mView;

    private List<Presenter> presenters = new ArrayList<>();
    @SafeVarargs
    public final <Q extends Presenter<T>> void requestPresenter(Q... cls){
        for (Q cl : cls) {
            cl.attachView(mView);
            presenters.add(cl);
        }
    }

    public PowerPresenter(T mView) {
        this.mView = mView;
    }

    @Override
    public void destroy() {
        for(Presenter presenter : presenters) { presenter.destroy(); }}}Copy the code

I’m just asking you if this code is simple, if it’s easy. It is also a subclass of WrapperPresenter, which means we use BaseAct

  • First of all, his constructor needs a View and that View inherits from BaseView and what do we need to get that View for when the data operation is done
  • Then we see that requestPresenter is a way of passing in a data that can handle multiple pages and multiple data requests. Simply pass in the request we need through the presenter we wrote earlier. You don’t need to write a presenter. To achieve reuse.
  • The third highlight is his perfect bar view connection. Since each data request has a presenter and a View, this class uses the constructor to pass in the view and then attaches the view by iterating through the data.
  • Also in destroy, the data is unbound.
How to complete single-page multi-data operation

On the code, simple violence or the previous BannerAct modified into a single page multiple data request

public class BannerAct extends BaseMvpAct<PowerPresenter> implements BannerView {
    private BannerPresenter bannerPresenter;

    @Override
    public void showLoading() {

    }

    @Override
    public void hideLoading() {

    }

    @Override
    public void showError(String message) {
        Log.i("cuieney"."showError: ");
    }

    @Override
    public void render(BannerBean bean) {
        Log.i("cuieney"."render: "+bean.toString());
    }

    @Override
    public void initialize() {
        bannerPresenter.initialize("dsds");
    }

    @Override
    public PowerPresenter createP() { PowerPresenter presenter = new PowerPresenter<>(this); bannerPresenter = new BannerPresenter(); ... [here you can add whatever you need presenter)... presenter. RequestPresenter (bannerPresenter);return presenter;
    }

    @Override
    public int addContentView() {
        return0; }}Copy the code

As you can see from the above code, we are implementing the createP method in the parent class, And then we achieved the reuse of BannerPresenter by creating PowerPresenter and adding the BannerPresenter network request that we needed to the requestPresenter request, just a few lines of code.

ending

It’s time to say goodbye again. I hope you can correct the above article if you see something wrong and need to improve it. In fact, this article is about a way of thinking, I just a method. You could write a better PowerPresenter based on your own structure.)