A preface.

Have you ever seen an Activity/Fragment with hundreds or thousands of lines of code that are completely unmaintainable?

Have you ever encountered a situation where you can’t write the code logic first because the background interface hasn’t been written yet?

Have you ever encountered the frustration of unit testing a project written with an MVC architecture?

If you are still writing in MVC mode, please switch to MVP mode first!

MVC architecture

MVC architecture pattern initially took root in server-side Web development, and gradually became competent for client-side Web development. Later, since Android projects are composed of XML and Activity/Fragment, Android developers gradually began to use MVC architecture pattern to develop applications.

M layer: Model layer (Model), mainly entity class, database, network and other existing layer, Model will send new data to view layer, users get data response.

V layer: View layer, generally refers to the VIEW interface represented by XML. Displays data from the Model layer. Events such as user clicks are passed from the View layer to the Controller layer.

Layer C: Controller layer, generally represented by Activity/Fragment. Layer C is mainly connected to layer V and layer M. Layer C receives the event request sent by layer V, obtains data from layer M and presents it to layer V.

As can be seen from the figure above, M layer and V layer are connected, and activities sometimes act as both the control layer and the view layer, resulting in a difficult project maintenance.

1. Advantages and disadvantages of MVC architecture
A. disadvantages
  1. Layer M and Layer V are connected without decoupling, which makes maintenance difficult.

  2. Too much code in an Activity/Fragment to maintain.

There is a lot of display code for the View UI in an Activity, so the View View and the Activity controller are not completely separated. When the Activity class is overloaded, it becomes difficult to manage and maintain. Especially when the state data of the UI gets mixed up with the persistent data and becomes very messy.

Advantages of B.
  1. The control layer and View layer are operated in the Activity, data operation is convenient.

  2. Module responsibilities are clearly divided. It is mainly divided into three modules M,V and C.

MVP structure

MVP is the Model,View,Presenter architecture. It looks like MVC, but it’s not. It can be seen from the figure above that the Model layer and View layer are not connected, completely decoupled.

The View layer notifies the Presenter layer of the event when the user touches the interface. The Presenter layer notifies the Model layer of the event. The Model layer processes the event and sends the result to the Presenter layer. It’s a whole process.

M layer: The Model layer, which acts like the M layer in MVC.

V layer: View layer. In MVC, V layer only contains XML files, while in MVP, V layer contains XML,Activity and Fragment. In theory, V layer does not involve any logic, only responsible for interface changes, try to put logic processing in M layer.

P layer: The notification layer (Presenter), the main function of P layer is to connect V layer and M layer, plays a role of notification transfer data.

1. Strengths and weaknesses of the MVP architecture
A. disadvantages
  1. The MVP has too many interfaces.

  2. Each feature requires several more files than MVC.

  3. If multiple server interfaces are requested in a single interface, the interface file will implement many callback interfaces, resulting in cumbersome code.

  4. If you change the data source and parameters in the request, you can cause more code changes.

  5. Additional code complexity and learning costs.

Advantages of B.
  1. Module responsibility division is obvious, the hierarchy is clear, the interface function is clear.

  2. The Model layer and View layer are separated and decoupled. Modify the View without affecting the Model.

  3. High functional reuse, convenient. A Presenter can be used for multiple views without changing the Presenter logic.

  4. Conducive to test-driven development, previous Android development was difficult to unit test.

  5. If the background interface is not written, but the return data type is known, it is possible to write the full function of the interface.

Iv. MVP Architecture Combat (Real guns)

1. Simple writing of MVP three-layer code

Then I pile up the entire structure of MVP bit by bit, from simple to complex. When the user clicks the Button, the Presenter layer notifys the Model layer to request processing of network data. After processing, the Model layer sends the resulting data to the Presenter layer, which notifys the View layer The post-View layer changes what the TextView displays.

<? xml version="1.0" encoding="utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".view.SingleInterfaceActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="100px"
        android:text="Please click on the top button to get the data" />
</LinearLayout>
Copy the code

Next is the Activity code, which is to get Button and TextView control, and then do Button listening, first simple write, while slowly increasing the code.

public class SingleInterfaceActivity extends AppCompatActivity {

    private Button button;
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_single_interface);
        button = findViewById(R.id.button);
        textView = findViewById(R.id.textView);

        button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } }); }}Copy the code

Here is the Model layer code. This web request uses the open API of wanAndroid website, which has the article front page list interface. The SingleInterfaceModel file contains a method called getData. The first parameter, curPage, is to retrieve the page of data, and the second parameter, callback, is to notify the Presenter callback from the Model layer.

public class SingleInterfaceModel {
    
    public void getData(int curPage, final Callback callback) {
        NetUtils.getRetrofit()
                .create(Api.class)
                .getData(curPage)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<ArticleListBean>() {
                    @Override
                    public void onCompleted() {
                        LP.w("completed");
                    }

                    @Override
                    public void onError(Throwable e) {
                        callback.onFail("Error occurred");
                    }

                    @Override
                    public void onNext(ArticleListBean bean) {
                        if (null == bean) {
                            callback.onFail("Error occurred");
                        } else if(bean.errorCode ! = 0) { callback.onFail(bean.errorMsg); }else{ callback.onSuccess(bean); }}}); }}Copy the code

The Callback file contains the following contents. Inside a successful a failed callback interface, parameters are generic, why the use of generic I don’t need to say it.

public interface Callback<K, V> {
    void onSuccess(K data);

    void onFail(V data);
}
Copy the code

Next comes the Presenter layer code. The SingleInterfacePresenter class constructor directly new a Model layer object for calls from the Presenter layer to the Model layer. The SingleInterfacePresenter class method getData is then used to interconnect with the Model.

public class SingleInterfacePresenter {
    private final SingleInterfaceModel singleInterfaceModel;

    public SingleInterfacePresenter() { this.singleInterfaceModel = new SingleInterfaceModel(); } public void getData(int curPage) { singleInterfaceModel.getData(curPage, new Callback<ArticleListBean, String>() {@override public void onSuccess(ArticleListBean loginResultBean) { @override public void onFail(String errorMsg) {// If the Model layer fails to request data, the code to notify the View layer should be implemented}}); }}Copy the code

At this point,MVP’s three simple layers of partial code are complete. So how do you call each other through the whole process. Let’s change the original SingleInterfaceActivity code to hold the Presenter layer object so that the View layer can call the Presenter layer. The modified code is as follows.

public class SingleInterfaceActivity extends AppCompatActivity {

    private Button button;
    private TextView textView;
    private SingleInterfacePresenter singleInterfacePresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_single_interface);
        button = findViewById(R.id.button);
        textView = findViewById(R.id.textView);

        singleInterfacePresenter = new SingleInterfacePresenter();
        button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { singleInterfacePresenter.getData(0); }}); }}Copy the code

As you can see from all the above code, when the user clicks the button, the View layer button’s listener execution calls the Presenter layer object’s getData method, and the Presenter layer object’s getData method calls the Model layer object’s GET method The Data method performs network requests and logical processing, calling back success or failure results via the Callback interface to the Presenter layer, which in turn notifies the View layer to change the interface. However, the SingleInterfacePresenter class cannot notify the View layer when it receives the results from the Model layer because SingleInterfacePresenter does not hold objects in the View layer. (If the button is clicked at this point, the log-successful network request will be printed at lp.w () below)

public class SingleInterfacePresenter {
    private final SingleInterfaceModel singleInterfaceModel;

    public SingleInterfacePresenter() { this.singleInterfaceModel = new SingleInterfaceModel(); } public void getData(int curPage) { singleInterfaceModel.getData(curPage, new Callback<ArticleListBean, String>() {@override public void onSuccess(ArticleListBean loginResultBean) {// If the Model layer requests data successfully, the code to notify the View layer should be executed here // lp.w () is a simple onelogPrint the LP w. (loginResultBean. ToString ()); } @override public void onFail(String errorMsg) {// If the Model layer fails to request data, the code to notify the View layer should be implemented}}); }}Copy the code

The code is written here. The author first submits the code to github(github.com/serge66/MVP…). Github will have a submission record. If you want to see the code at this time, you can clone the code at this time according to the submission record “first modification”.

2. Communication bridge of P layer and V layer

Now that layer P does not hold layer V objects, layer V cannot be told to change the interface, so the MVP architecture continues to evolve. In the MVP architecture, we write an interface for each Activity/Fragment. This interface needs to be held by the Presenter layer, and P layer uses this interface to notify V layer of changes to the interface. The interface contains both successful and failed callbacks, and the Activity/Fragment interface is implemented so that the P layer notifies the V layer.

public interface SingleInterfaceIView {
    void showArticleSuccess(ArticleListBean bean);

    void showArticleFail(String errorMsg);
}
Copy the code

A complete project is bound to have many functional interfaces, so we should pull out an IView public interface and let all activities/fragments implement it indirectly. The IVew public interface is used to inherit interfaces from the View layer, not the View itself. Because it defines the specification of the interface, the other interface is the specification of the defined class.

/** * @description: Public interface is used to inherit the View interface, note, not the View itself. * @author: [email protected] * @time: 2018/11/22 17:26 */ public interface IView {}Copy the code

This interface can write some methods common to all Activigy/Fragment methods. We inherit the IView interface from SingleInterfaceIView.

public interface SingleInterfaceIView extends IView {
    void showArticleSuccess(ArticleListBean bean);

    void showArticleFail(String errorMsg);
}
Copy the code

The same goes for the Model and Presenter layers.

public interface IModel {
}
Copy the code
public interface IPresenter {
}
Copy the code

Now the Model layer of the project is a SingleInterfaceModel class, which is held by the P layer. For object-oriented design, it is well known to use interfaces to achieve decoupling, so we need to write an inheriting interface for the SingleInterfaceModel class. Here’s the code.

public interface ISingleInterfaceModel extends IModel {
    void getData(int curPage, final Callback callback);
}
Copy the code

Thus, the SingleInterfaceModel class is modified as follows.

public class SingleInterfaceModel implements ISingleInterfaceModel {

    @Override
    public void getData(int curPage, final Callback callback) {
        NetUtils.getRetrofit()
                .create(Api.class)
                .getData(curPage)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<ArticleListBean>() {
                    @Override
                    public void onCompleted() {
                        LP.w("completed");
                    }

                    @Override
                    public void onError(Throwable e) {
                        callback.onFail("Error occurred");
                    }

                    @Override
                    public void onNext(ArticleListBean bean) {
                        if (null == bean) {
                            callback.onFail("Error occurred");
                        } else if(bean.errorCode ! = 0) { callback.onFail(bean.errorMsg); }else{ callback.onSuccess(bean); }}}); }}Copy the code

Similarly, the View layer holds the P-layer objects, and we need to modify the P-layer as well. However, the following code does not inherit IPresenter in the same way that the ISingleInterfaceModel interface inherits IModel. Note that I have put the inheritance of IPresenter elsewhere, which I will explain later.

public interface ISingleInterfacePresenter {
    void getData(int curPage);
}

Copy the code

Then the SingleInterfacePresenter class is modified as follows:

public class SingleInterfacePresenter implements ISingleInterfacePresenter {
    private final ISingleInterfaceModel singleInterfaceModel;

    public SingleInterfacePresenter() { this.singleInterfaceModel = new SingleInterfaceModel(); } @Override public void getData(int curPage) { singleInterfaceModel.getData(curPage, new Callback<ArticleListBean, String>() {@override public void onSuccess(ArticleListBean loginResultBean) {// If the Model layer requests data successfully, the code to notify the View layer should be executed here // lp.w () is a simple onelogPrint the LP w. (loginResultBean. ToString ()); } @override public void onFail(String errorMsg) {lp.w (errorMsg); }}); }}Copy the code
3. Lifecycle adaptation

At this point, the interfaces for each of the three LAYERS of MVP have been written. But the bridge between P floor and V floor has not been built, this slowly, a good high-rise building is built step by step. The IPresenter interface above is not inherited by any other class, so let’s talk about that. P layer is connected to V layer, and the life cycle of V layer should also be adapted to P layer. Each function of P layer should be adapted to the life cycle, and the adaptation of the life cycle can be put in the IPresenter interface. The P layer holds the V layer object, which we put in the generic type. Here’s the code.

Public interface IPresenter<T extends IView> {/** * @attachView */ void attachView(T view); /** * detachView */ void detachView(); /** * Check whether the View has been destroyed ** @return
     */
    boolean isViewAttached();
    
}
Copy the code

The IPresenter interface requires class inheritance from all P layer implementations. The lifecycle is common, so an abstract base class, BasePresenter, can be extracted to implement the IPresenter interface.

public abstract class BasePresenter<T extends IView> implements IPresenter<T> {
    protected T mView;

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

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

    @Override
    public boolean isViewAttached() {
        return mView != null;
    }
}

Copy the code

At this point, the SingleInterfacePresenter class code change is as follows. The SingleInterfaceIView in the generic can be understood as the corresponding Activity, and the P layer completes the communication with the V layer.

public class SingleInterfacePresenter extends BasePresenter<SingleInterfaceIView> implements ISingleInterfacePresenter {  private final ISingleInterfaceModel singleInterfaceModel; publicSingleInterfacePresenter() { this.singleInterfaceModel = new SingleInterfaceModel(); } @Override public void getData(int curPage) { singleInterfaceModel.getData(curPage, new Callback<ArticleListBean, String>() {@override public void onSuccess(ArticleListBean loginResultBean) {// If the Model layer requests data successfully, the code to notify the View layer should be executed here // lp.w () is a simple onelogPrint the LP w. (loginResultBean. ToString ());if(isViewAttached()) { mView.showArticleSuccess(loginResultBean); }} @override public void onFail(String errorMsg) {lp.w (errorMsg);if(isViewAttached()) { mView.showArticleFail(errorMsg); }}}); }}Copy the code

At this point, the connection bridge between P layer and V layer has been built, but it has not been completed. We need to write BaseMVPActvity for all activities to inherit and process the same logic of activities in a unified manner. Use the IPresenter generics in BaseMVPActvity, because each Activity needs to hold a P-layer object, so here we pull the P-layer object out and put it in BaseMVPActvity. At the same time, BaseMVPActvity also needs to inherit IView for the life cycle of P layer to V layer. Here’s the code.

public abstract class BaseMVPActivity<T extends IPresenter> extends AppCompatActivity implements IView {

    protected T mPresenter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initPresenter();
        init();
    }

    protected void initPresenter() { mPresenter = createPresenter(); // Bind the life cycleif(mPresenter ! = null) { mPresenter.attachView(this); } } @Override protected voidonDestroy() {
        if(mPresenter ! = null) { mPresenter.detachView(); } super.onDestroy(); } /** * create a Presenter ** @return
     */
    protected abstract T createPresenter();

    protected abstract void init();

}
Copy the code

Next, let SingleInterfaceActivity implement the BaseMVPActivity.

public class SingleInterfaceActivity extends BaseMVPActivity<SingleInterfacePresenter> implements SingleInterfaceIView {  private Button button; private TextView textView; @Override protected voidinit() {
        setContentView(R.layout.activity_single_interface);
        button = findViewById(R.id.button);
        textView = findViewById(R.id.textView);

        button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mPresenter.getData(0); }}); } @Override protected SingleInterfacePresentercreatePresenter() {
        returnnew SingleInterfacePresenter(); } @Override public void showArticleSuccess(ArticleListBean bean) { textView.setText(bean.data.datas.get(0).title); } @Override public void showArticleFail(String errorMsg) { Toast.makeText(this, errorMsg, Toast.LENGTH_SHORT).show(); }}Copy the code

At this point, the entire simplified process of MVP architecture is complete.

The code is written here. The author first submits the code to github(github.com/serge66/MVP…). Github will have a submission record. If you want to see the code at this time, you can clone the code at this time according to the submission record.

4. Optimize the MVP architecture

Above is the MVP directory, from the directory we can see a function point (network request)MVP three layers each have two files to write, compared to MVC is really difficult to write, which is why some people do not want to write MVP, prefer MVC.

So we can optimize this a little bit. A Contract is a unified management interface that manages the View and Presenter interfaces of a page. A Contract reduces the creation of certain files, such as the interface files of P layer and V layer.

Then we can put P ISingleInterfacePresenter interface layer and V SingleInterfaceIView interface file deleted, add SingleInterfaceContract file. Here’s the code.

public interface SingleInterfaceContract {


    interface View extends IView {
        void showArticleSuccess(ArticleListBean bean);

        void showArticleFail(String errorMsg);
    }

    interface Presenter {
        void getData(int curPage);
    }


}
Copy the code

At this point, the SingleInterfacePresenter and SingleInterfaceActivity code changes are as follows.

public class SingleInterfacePresenter extends BasePresenter<SingleInterfaceContract.View>
        implements SingleInterfaceContract.Presenter {

    private final ISingleInterfaceModel singleInterfaceModel;

    public SingleInterfacePresenter() { this.singleInterfaceModel = new SingleInterfaceModel(); } @Override public void getData(int curPage) { singleInterfaceModel.getData(curPage, new Callback<ArticleListBean, String>() {@override public void onSuccess(ArticleListBean loginResultBean) {// If the Model layer requests data successfully, the code to notify the View layer should be executed here // lp.w () is a simple onelogPrint the LP w. (loginResultBean. ToString ());if(isViewAttached()) { mView.showArticleSuccess(loginResultBean); }} @override public void onFail(String errorMsg) {lp.w (errorMsg);if(isViewAttached()) { mView.showArticleFail(errorMsg); }}}); }}Copy the code
public class SingleInterfaceActivity extends BaseMVPActivity<SingleInterfacePresenter>
        implements SingleInterfaceContract.View {

    private Button button;
    private TextView textView;

    @Override
    protected void init() {
        setContentView(R.layout.activity_single_interface);
        button = findViewById(R.id.button);
        textView = findViewById(R.id.textView);

        button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mPresenter.getData(0); }}); } @Override protected SingleInterfacePresentercreatePresenter() {
        returnnew SingleInterfacePresenter(); } @Override public void showArticleSuccess(ArticleListBean bean) { textView.setText(bean.data.datas.get(0).title); } @Override public void showArticleFail(String errorMsg) { Toast.makeText(this, errorMsg, Toast.LENGTH_SHORT).show(); }}Copy the code

The code is written here. The author first submits the code to github(github.com/serge66/MVP…). Github will have a submission record. If you want to see the code at this time, you can clone the code at this time according to the submission record “third modification”.

5. Single page multiple network requests

The MVP encapsulation above only applies to the case of one network request on a single page, and is not suitable when there are two network requests on the same interface. To this end, we create a MultipleInterfaceActivity again for instructions. The layout in XML is two buttons and two TextViews that you can click on to make a web request.

<? xml version="1.0" encoding="utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".view.MultipleInterfaceActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50px"
        android:text="Please click on the top button to get the data" />

    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="100px"
        android:text="Click" />

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50px"
        android:text="Please click on the top button to get the data" />
</LinearLayout>
Copy the code

MultipleInterfaceActivity class code temporarily as follows.

public class MultipleInterfaceActivity extends BaseMVPActivity {

    private Button button;
    private TextView textView;
    private Button btn;
    private TextView tv;


    @Override
    protected void init() {
        setContentView(R.layout.activity_multiple_interface);

        button = findViewById(R.id.button);
        textView = findViewById(R.id.textView);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });


        btn = findViewById(R.id.btn);
        tv = findViewById(R.id.tv);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
    }

    @Override
    protected IPresenter createPresenter() {
        returnnull; }}Copy the code

If there are multiple network requests on a page, the BaseMVPActivity generic inherits multiple parameters. Does the framework of the BaseMVPActivity code still implement this requirement? We can think of multiple network requests as a single network request, encapsulated as a MultiplePresenter, which is inherited to BasePresenter for lifecycle adaptation. The purpose of this MultiplePresenter class is to accommodate multiple presenters, connected to the same View. Here’s the code.

public class MultiplePresenter<T extends IView> extends BasePresenter<T> {
    private T mView;

    private List<IPresenter> presenters = new ArrayList<>();

    @SafeVarargs
    public final <K extends IPresenter<T>> void addPresenter(K... addPresenter) {
        for (K ap : addPresenter) {
            ap.attachView(mView);
            presenters.add(ap);
        }
    }

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

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

Because you need multiple network requests in the MultiplePresenter class, we’ll use two network request interfaces for the moment when we illustrate. MultipleInterfaceActivity class code in the following.

public class MultipleInterfaceActivity extends BaseMVPActivity<MultiplePresenter>
        implements SingleInterfaceContract.View, MultipleInterfaceContract.View {

    private Button button;
    private TextView textView;
    private Button btn;
    private TextView tv;
    private SingleInterfacePresenter singleInterfacePresenter;
    private MultipleInterfacePresenter multipleInterfacePresenter;


    @Override
    protected void init() {
        setContentView(R.layout.activity_multiple_interface);

        button = findViewById(R.id.button);
        textView = findViewById(R.id.textView);

        button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { singleInterfacePresenter.getData(0); }}); btn = findViewById(R.id.btn); tv = findViewById(R.id.tv); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { multipleInterfacePresenter.getBanner(); }}); } @Override protected MultiplePresentercreatePresenter() {
        MultiplePresenter multiplePresenter = new MultiplePresenter(this);

        singleInterfacePresenter = new SingleInterfacePresenter();
        multipleInterfacePresenter = new MultipleInterfacePresenter();

        multiplePresenter.addPresenter(singleInterfacePresenter);
        multiplePresenter.addPresenter(multipleInterfacePresenter);
        returnmultiplePresenter; } @Override public void showArticleSuccess(ArticleListBean bean) { textView.setText(bean.data.datas.get(0).title); } @Override public void showArticleFail(String errorMsg) { Toast.makeText(this, errorMsg, Toast.LENGTH_SHORT).show(); } @Override public void showMultipleSuccess(BannerBean bean) { tv.setText(bean.data.get(0).title); } @Override public void showMultipleFail(String errorMsg) { Toast.makeText(this, errorMsg, Toast.LENGTH_SHORT).show(); }}Copy the code

At this point, the MVP framework is almost complete. If you want to optimize again, there are some things that can be optimized. For example, when a View is destroyed, it now just sets the View object in the P layer to null and does not continue to notify the M layer. If the View is destroyed while layer M is still in the request network, you can add a general function to cancel network requests. Here is just one example. Everyone’s definition of MVP is different, and the MVP structure is not set in stone. What suits your project is the best.

6. Complete project address

The full project has been submitted to github(github.com/serge66/MVP…) , please check it out if necessary.

5. Reference materials

Step by step take you to MVP mastery

Build the MVP framework from zero to one

How highly reusable is the Presenter layer

6. Subsequent

<<MVVM architecture from beginner to Master – Real guns >> stay tuned ~~~

Original article, from the Vitamio (http://blog.csdn.net/vitamio), reprint please indicate the source.