Saturday, February 18, 2017

MVP is weird

So the more I read about MVP architectures as they apply to Android, the more I see things like this:

Presenter.java

class Presenter {



    DataSource ds = DataSource.get();
    View v;

    void bindView(View v) {
        this.v = v;
    }

    void unbindView() {
        this.v = null;
    }

    void doSomething() {
        v.onDoSomething();
    }

    void doSomethingElse() {
        ds.dataToObservable()
            .subscribe(data -> {
                v.onDoSomethingElse(data.stuff);
            });
    }

    interface View {
        void onDoSomething();

        void onDoSomethingElse(Stuff stuff);
    }
}


View.java


class View implements Presenter.View {

    Presenter presenter = Presenter.create();

    void onStart() {
        presenter.bindView(this); 
        button.setOnClickListener(v -> {
            if (condition) {
                presenter.doSomething();
            } else {
                presenter.doSomethingElse();
            }
        });
    } 

    void onStop() {
        presenter.unbindView(); 
        button.setOnClickListener(null);
    } 

    @Override public void onDoSomething() {
      doStuff();
    }

    @Override public void onDoSomethingElse() {
      doOtherStuff();
    }
}

That was a difficult process to write all of that psuedocode in Blogger. Not fun.
I'm curious to know where the Android practice of making the Activity or Fragment or whatever implement the entire View contract began. It seems like it clutters up the Activity with all of these callback methods that you can't really figure out where they are coming from or where they go to.

It seems to me like it would be much more efficient to implement these callbacks in separate contracts for the presenter instead of one large one, and have each presenter method accept a different contract. In doing so, you can keep the callback in a visually easy to read place - passed in with the method call to the presenter.

This way, while you are jumping around the various views and dealing with the already difficult to follow lifecycle methods, you can rest assured that your presenter layer logic won't just come out of the blue.

You can easily then trace the presenter logic by simply using Android studio to open the source file for the presenter, and you can see just where your callback is used.

Presenter.java

class Presenter {



    DataSource ds = DataSource.get();

    void doSomething(Something something) {
        something.onDoSomething();
    }

    void doSomethingElse(SomethingElse somethingElse) {
        ds.dataToObservable()
            .subscribe(data -> {
                somethingElse.onDoSomethingElse(data.stuff);
            });
    }

    interface Something {
        void onDoSomething();
    }
    
    interface SomethingElse {

        void onDoSomethingElse(Stuff stuff);
    }
}


View.java


class View {

    Presenter presenter = Presenter.create();

    void onStart() {
        button.setOnClickListener(v -> {
            if (condition) {
                presenter.doSomething(() -> doStuff());
            } else {
                presenter.doSomethingElse(() -> doOtherStuff());
            }
        });
    } 

    void onStop() {
        button.setOnClickListener(null);
    }
}

Sure it nests callbacks, which can visually not be as nice, but the code that responds to the presenter's action stays very local to where the presenter is invoked. And if you have lambdas, you can clean up the code to the point that you would barely notice the callback chain.

You'll have to make sure you release memory and subscriptions for your presenter onStop so that you don't accidentally hang on to these callbacks, but then again, you should be doing that already.

Visually your code will be easier to interpret and easier to read. It saves you from having to search through files just to find where you override a callback, and saves you from having to dig through files to find out which interface provides which contract for which presenter.

Brain dump off.

========================
Follow pyamsoft around the Web for updates and announcements about the newest applications!
Like what I do?

Send me an email at: pyam.soft@gmail.com
Or find me online at: https://pyamsoft.blogspot.com

Follow my FaceBook Page
Follow my Google+ Page
=========================