Framework (1) - Login examples and Google official examples to explain the MVP model

Introduction to this article

In Android development, after sorting out the requirements, what you need to do is not to write your first line of code immediately, but to design the technical framework of the entire project first. This article mainly explains the MVP model through login examples and Google official examples.

Table of contents

  • Why carry out technical framework design?
  • MVP model
  • Login example to explain MVP model
  • Google official examples explain MVP model
  • Source code download address

Why carry out technical framework design?

  • Modular functionality

    Make the program modular, that is: high internal aggregation and low coupling between modules improve development efficiency, enable each module to perform its own duties, and improve the readability, scalability, maintainability and security of the code.

  • Improve development efficiency

    It allows multiple people to collaboratively develop the same module. After designing the interface, developers only need to focus on a certain point (view display, business logic/data processing).

  • Improve testing efficiency

    It is convenient for testing. Each module can be tested individually. It is not necessary to complete all modules before testing.

  • Improve code maintainability

    You can quickly locate which module the problem belongs to, make changes, and change the current module as little as possible to affect other functions, reduce the occurrence of concurrent bugs, and reduce the workload of testing.

Remember: don’t design for the sake of design, otherwise it will increase the amount of development.
Insert image description here

MVP model

definition

MVP stands for Model-View-Presenter mode, which is used for layered development of applications.

  • Model (Model)
    The model is the part of the application that is used to process application data logic. Usually the model object is responsible for accessing data and business logic in the database (for example: getting data from a network server and processing it), and updating controls when the data changes. device.

  • View -
    View is the part of the application that handles interface display, including updating and retrieving interface content, and processing of user-triggered events.

  • Presenter (Controller)
    Controller acts on models and views. It controls the flow of data to model objects and updates the view when the data changes. It separates the view from the model.

Calling relationship between MVPs

M calls P, P calls M, M returns the result to P, and P returns the result to V. V cannot use M directly, completely separating the interface from business logic or data processing.
Insert image description here

MVP mode execution sequence

The execution sequence is explained in 3 situations. See the figure below for details.
Insert image description here

Role description of MVP in android project

Insert image description here

actual case

Login function implemented in MVP mode

The login function implementation interface enters the user name and password, and then compares it with the simulated user name obtained from the server, and then returns the login result to the interface.
The interface is shown as follows:
Insert image description here
the corresponding relationship between roles, classes and interfaces
Insert image description here

function call procedure
Insert image description herecode

  • View interface
public interface IUserLoginView {
    
    
     void setSuccessInfo();
     void setErrorInfo(int iErrorCode);
}
  • View XML file
<?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:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="案例说明:"
        android:textColor="@android:color/holo_red_dark"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="登录功能的MVPDemo\n1、具体分为3层View-Presenter-Model\n2、V-P层传数据采用函数的参数传参\n3、M层模拟从网络获取数据。\n4、正确用户名和密码分别为:mvp,123456"
        android:textColor="@android:color/holo_red_dark"/>

    <EditText
        android:id="@+id/et_username"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="mvp" />

    <EditText
        android:id="@+id/et_pwd"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="123456" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="Login"
        android:onClick="Login"/>
</LinearLayout>

  • View-Activity
public  class LoginMVPDemoActivity extends AppCompatActivity implements IUserLoginView {
    
    
    private EditText etUserName;
    private EditText etPwd;

    IUserLoginPresenter bUserLoginPresenter = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login_mvpdemo);

        etUserName = (EditText) findViewById(R.id.et_username);
        etPwd = (EditText) findViewById(R.id.et_pwd);

        bUserLoginPresenter = new UserLoginPresenter(this);
    }

    @Override
    public void setSuccessInfo() {
    
    
        Toast.makeText(this,"登录成功!",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void setErrorInfo(int iErrorCode) {
    
    
        if(iErrorCode == 1){
    
    
            Toast.makeText(this,"登录失败:用户名不存在或不正确",Toast.LENGTH_SHORT).show();
        }else if(iErrorCode == 2){
    
    
            Toast.makeText(this,"登录失败:密码不正确",Toast.LENGTH_SHORT).show();
        }

    }

    public void Login(View v){
    
    
        bUserLoginPresenter.login(etUserName.getText().toString(),
                etPwd.getText().toString());
    }
}

  • Presenter interface-IUserLoginPresenter
public interface IUserLoginPresenter {
    
    
     void login(String username, String strPwd);
}
  • Presenter interface-OnUserLoginListener
public interface OnUserLoginListener {
    
    
     void onUserLoginSuccess();
     void onUserLoginError(int iErrorCode);
}
  • Presenter concrete class
public class UserLoginPresenter implements IUserLoginPresenter,OnUserLoginListener{
    
    
    IUserLoginMode bUserLoginMode = null;
    IUserLoginView bUserLoginView = null;
    public UserLoginPresenter(IUserLoginView bUserLoginView){
    
    
        bUserLoginMode = new UserLoginMode();
        this.bUserLoginView = bUserLoginView;
    }

    @Override
    public void onUserLoginSuccess() {
    
    
        bUserLoginView.setSuccessInfo();
    }

    @Override
    public void onUserLoginError(int iErrorCode) {
    
    
        bUserLoginView.setErrorInfo(iErrorCode);
    }

    @Override
    public void login(String username, String strPwd) {
    
    
        bUserLoginMode.handleLogin(username,strPwd,this);
    }
}
  • Model interface
public interface IUserLoginMode {
    
    
     void handleLogin(String username, String strPwd,
                            OnUserLoginListener bOnUserLoginListener);
}
  • Model implementation class
public class UserLoginMode implements IUserLoginMode {
    
    
    @Override
    public void handleLogin(String username, String strPwd,
                            OnUserLoginListener bOnUserLoginListener) {
    
    
        String s_username = "mvp";
        String s_strPwd ="123456";
        //用户名不存在
        if(!username.equals(s_username)){
    
    
            bOnUserLoginListener.onUserLoginError(1);
        } else if(username.equals(s_username) && s_strPwd.equals(strPwd)){
    
    
            bOnUserLoginListener.onUserLoginSuccess();
        }else if(username.equals(s_username) && !s_strPwd.equals(strPwd)){
    
    
            //密码不正确
            bOnUserLoginListener.onUserLoginError(2);
        }

    }
}

Google official MVPDemo

The official demo implements the processing of the data loading process. The interface shows that the data has started to be loaded, the data is loading, and the data loading is completed and displayed on the interface.
The interface is displayed as follows:
Insert image description here
The difference between the official demo and the login case

  • The model does not abstract the interface and directly implements it concretely.
  • Add a contract between v and p. The original interfaces of v and p are classified into the two interfaces of contact. Based on the v and p interfaces, the basic v interface and p interface are abstracted to make the coupling between v and p lower. , increasing the scalability and maintainability of the program.

Correspondence between roles, interfaces and classes
Insert image description here
Function calling process
Insert image description here

  • View interface
public interface BaseView<T> {
    
    
    void setPresenter(T presenter);
}
  • Presenter interface
public interface BasePresenter {
    
    
    void start();
}
  • Contract interface
public interface UserInfoContract {
    
    

    interface View extends BaseView<Presenter>{
    
    

        void showLoading();//展示加载框

        void dismissLoading();//取消加载框展示

        void showUserInfo(UserInfoModel userInfoModel);//将网络请求得到的用户信息回调

        String loadUserId();//假设接口请求需要一个userId
    }

    interface Presenter extends BasePresenter {
    
    
        void loadUserInfo();
    }

}
  • View-XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="案例说明:"
        android:textColor="@android:color/holo_red_dark"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Google官方提供的MVPDemo\n1、具体分为4View-Crontract-Presenter-Model\n2、contract层处于V层和P层中间,实现了原本在V层和P层的两个接口,V层和P层的接口是在Contract中对应接口的基础上再抽象一层,
使V层和P层的耦合性更低,灵活性更高。\n3、V-P层传参采用接口函数传参\n4、此Demo重点在于V层和P层的分离,M层的较少。"
        android:textColor="@android:color/holo_red_dark"/>

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="Hello World!" />

    <TextView
        android:id="@+id/tv_age"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

    <TextView
        android:id="@+id/tv_address"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
</LinearLayout>

  • View-Activity
public class GoogleMVPDemoActivity extends AppCompatActivity implements UserInfoContract.View {
    
    
    private TextView tv_name;
    private TextView tv_age;
    private TextView tv_address;

    private UserInfoContract.Presenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_google_mvpdemo);

        tv_name = (TextView) findViewById(R.id.tv_name);
        tv_age = (TextView) findViewById(R.id.tv_age);
        tv_address = (TextView) findViewById(R.id.tv_address);
        //通知P层要
        new UserInfoPresenter(this);
        presenter.start();
    }

    @Override
    public void showLoading() {
    
    
        Toast.makeText(this, "正在加载", Toast.LENGTH_LONG).show();
    }

    @Override
    public void dismissLoading() {
    
    
        Toast.makeText(this, "加载完成", Toast.LENGTH_LONG).show();
    }

    @Override
    public void showUserInfo(UserInfoModel userInfoModel) {
    
    
        if (userInfoModel != null) {
    
    
            tv_name.setText(userInfoModel.getName());
            tv_age.setText(String.valueOf(userInfoModel.getAge()));
            tv_address.setText(userInfoModel.getAddress());
        }
    }

    @Override
    public String loadUserId() {
    
    
        return "1000";//假设需要查询的用户信息的userId是1000
    }

    @Override
    public void setPresenter(UserInfoContract.Presenter presenter) {
    
    
        this.presenter = presenter;
    }
}
  • Presenter concrete class
ublic class UserInfoPresenter implements UserInfoContract.Presenter {
    
    
    private UserInfoContract.View view;

    public UserInfoPresenter(UserInfoContract.View view) {
    
    
        this.view = view;
        view.setPresenter(this);
    }

    @Override
    public void loadUserInfo() {
    
    
        String userId = view.loadUserId();
        view.showLoading();//接口请求前显示loading
        //这里模拟接口请求回调-
        new Handler().postDelayed(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                //模拟接口返回的json,并转换为javaBean
                UserInfoModel userInfoModel = new UserInfoModel("小宝", 1, "杭州");
                view.showUserInfo(userInfoModel);
                view.dismissLoading();
            }
        }, 3000);
    }

    @Override
    public void start() {
    
    
        loadUserInfo();
    }

}
  • Model concrete class
public class UserInfoModel {
    
    
    private String name;
    private int age;
    private String address;

    public UserInfoModel(String name, int age, String address) {
    
    
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public String getAddress() {
    
    
        return address;
    }

    public void setAddress(String address) {
    
    
        this.address = address;
    }
}

Summarize

When analyzing the code, pay attention to the holding of objects between the two case MVPs, the transfer of objects and the way of transferring data (method parameter passing and method parameter passing)

Case download address

MVPDemo download address

Reference link

Illustrated MVC, MVP, MVVM patterns: examples to explain so you know clearly

Guess you like

Origin blog.csdn.net/li1500742101/article/details/105382015