Comprensión y uso del modo MVP

Tabla de contenido

1. Por qué usar el patrón MVP

1.1 Ejemplo de descripción

2. Cómo usar el patrón MVP

2.1 División de la implementación de MVP

2.2 Interfaz de comunicación implementada por MVP

2.3 Almacén de funciones realizado por MVP

3. Ventajas y desventajas del modelo MVP


1. Por qué usar el patrón MVP

En el desarrollo de Android, la responsabilidad principal de Actividad es cargar el diseño de la aplicación e inicializar la interfaz de usuario, aceptar y procesar las solicitudes de operación de los usuarios. Sin embargo, a medida que aumenta la complejidad de la interfaz y la lógica, las responsabilidades de la clase Activity continúan aumentando y se vuelven grandes e infladas. Entonces necesitamos usar el modelo MVP para resolver los problemas de confusión, redundancia y fuerte acoplamiento.

1.1 Ejemplo de descripción

La siguiente es una demostración del inicio de sesión del usuario

public class LoginActivity extends AppCompatActivity {
    EditText inputUserName;
    EditText inputPassword;
    Button btnLogin;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        //点击登录
        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //获取账户和密码
                final String userName = inputUserName.getText().toString();
                final String password = inputPassword.getText().toString();
                //判空
                boolean isEmptyPassword = userName == null || userName.length() == 0;
                //是否符合规范
                boolean isUserNameValid = Pattern.compile("^[A-Za-z0-9]{3,20}+$").matcher(userName).matches();
                boolean isPasswordValid = Pattern.compile("^[A-Za-z0-9]{3,20}+$").matcher(password).matches();
                
                if (isEmptyPassword) {
                    Toast.makeText(LoginActivity.this, "请输入帐号密码", Toast.LENGTH_SHORT).show();
                } else {
                    if (isUserNameValid && isPasswordValid) {
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                //..登录请求
                                boolean loginResult = false;
                                //登录结果
                                if (loginResult) {
                                    Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
                                } else {
                                    Toast.makeText(LoginActivity.this, "登录失败", Toast.LENGTH_SHORT).show();
                                }
                            }
                        }).start();
                    } else {
                        Toast.makeText(LoginActivity.this, "帐号密码格式错误", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });
    }
}

La implementación del servicio de inicio de sesión incluye: escuchar eventos de clic, obtener datos de entrada, verificar datos, procesar juicio vacío, solicitud de inicio de sesión y mostrar resultados de inicio de sesión. Puede ver claramente los problemas de confusión de código y acoplamiento pesado. Entonces, si lo cambiamos al modo MVP, ¿cómo dividirlo? En primer lugar, debemos entender lo que hace el Modelo/Vista/Presentador en el modo MVP.

2. Cómo usar el patrón MVP

MVP significa Modelo, Vista y Presentador.

  • El modelo es muy simple, para la carga de datos. Tales como operaciones de base de datos, consultas de archivos, solicitudes de red.
  • La capa Vista es responsable de mostrar los datos y la interacción del usuario. Las actividades y los fragmentos de MVP se reflejan en esta capa, como la carga de las vistas de la interfaz de usuario y la configuración de los monitores.
  • La capa Presentador maneja la distribución de varias lógicas.Después de recibir las instrucciones de retroalimentación de la interfaz de usuario de la capa Ver, la lógica de procesamiento de distribución se entrega a la capa Modelo para operaciones comerciales específicas.

2.1 División de la implementación de MVP

Después de comprender los principios básicos de implementación del patrón MVP, la función de inicio de sesión se puede dividir en:

1. Valor, número de cuenta y contraseña de EditText (capa de vista clara, no implica operaciones lógicas)
2. Juicio y verificación nulos (Presentador pero implica Vista, porque se utilizan el número de cuenta y la contraseña, a través de la forma de paso de parámetros)
3. Solicitud de inicio de sesión (un verdadero modelo, el procesamiento obviamente está en la capa de presentador)
4. Actualice la interfaz de usuario (capa de vista) 

Reescribimos el código de solicitud de inicio de sesión de esta manera.

Capa de modelo

public class LoginModel {
    
    public LoginModel() {
       
    }

    //回调的接口
    public interface OnLoginCallback{
        void onResponse(boolean success);
    }

    public void login(String username,String password,final OnLoginCallback onLoginCallback){
        //..登录请求
        boolean loginResult = false;
        //登录结果
        onLoginCallback.onResponse(loginResult);
    }
}

Ver capa

public class LoginActivity extends AppCompatActivity {
    EditText inputUserName;
    EditText inputPassword;
    Button btnLogin;
    LoginPresenter presenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        inputUserName = this.findViewById(R.id.et_username);
        inputPassword = this.findViewById(R.id.et_password);
        btnLogin = this.findViewById(R.id.bt_login);
        //创建Presenter
        presenter = new LoginPresenter(this);
        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //调用Presenter层,登录逻辑execureLogin()
                presenter.execureLogin(getEditorText(inputUserName),getEditorText(inputPassword));
            }
        });
    }
    //在View层获取输入数据
    private String getEditorText(EditText et) {
        return et.getText().toString();
    }
    //在View层显示结果
    public void notifyLoginResult(boolean loginResult) {
        if (loginResult) {
            showTips("登录成功");
        } else {
            showTips("登录失败");
        }
    }

    public void showTips(String verifyMsg) {
        Toast.makeText(LoginActivity.this, verifyMsg, Toast.LENGTH_SHORT).show();
    }
}

capa de presentador

public class LoginPresenter {
    private LoginActivity activity;
    private LoginModel model;
    private String verifyMsg;
    public LoginPresenter(LoginActivity activity) {
        //获取View层
        this.activity = activity;
        //获取model对象
        this.model = new LoginModel();
    }
    public void execureLogin(String username,String password){
        //逻辑类的方法
        boolean verifyBefore = verifyBeforeLogin(username,password);
        if (verifyBefore) {
            //调用login()实现网络请求
             model.login(username, password, new LoginModel.OnLoginCallback() {
                 //实现回调方法
                 @Override
                 public void onResponse(boolean success) {
                     //将结果给到View层
                     activity.notifyLoginResult(success);
                 }
             });
        }else {
            activity.showTips(verifyMsg);
        }
    }

    private boolean verifyBeforeLogin(String username, String password) {
        boolean isEmpty = isEmpty(username) || isEmpty(password);
        boolean isValid = isValid(username) && isValid(password);
        if (isEmpty) {
            verifyMsg = "请输入帐号或密码";
            return false;
        }
        if (isValid) {
            return true;
        }
        verifyMsg = "帐号或密码错误";
        return false;
    }

    private boolean isValid(String s) {
        return Pattern.compile("^[A-Za-z0-9]{3,20}+$").matcher(s).matches();
    }

}

Aunque la página se divide en tres capas según MVP, el acoplamiento en el código aún existe:

  • El presentador sostiene los objetos Vista (Actividad) y Modelo
  • Ver retiene objeto de presentador

2.2 Interfaz de comunicación implementada por MVP

El uso de la interfaz para lograr el propósito de desacoplamiento requiere que View y Presenter implementen interfaces para llamadas externas, respectivamente.

  • Los métodos que llama View para Presenter son notifyLoginResulty showTips;
  • Hay métodos que Presenter puede llamar para View executeLogin.

Proporcione métodos para llamadas externas en la interfaz, luego impleméntelos en View y Presenter respectivamente, y finalmente cambie el objeto contenedor a una interfaz. La implementación específica es la siguiente: 

Definir la clase de interfaz de IPresenter

public interface IPresenter {
    //执行登录的接口
    void execureLogin(String username,String password);
}

 Definir la clase de interfaz IView

public interface IView {
    //显示结果的接口
    void notifyLoginResult(boolean loginResult);
    void showTips(String verifyMsg);
}
//LoginPresenter实现IPresenter接口
public class LoginPresenter implements IPresenter{
    //原来的LoginActivity改为了IView
    private IView activity;
    ...

}

----------------------------------------------------------------------------------------


//LoginActivity 实现IView接口
public class LoginActivity extends AppCompatActivity implements IView{
    //将原来的LoginPresenter改为IPresenter
    IPresenter presenter;

...

}

2.3 Almacén de funciones realizado por MVP

MVP introduce los conceptos de BaseInterface y Contract. La interfaz definida debe heredar de IView e IPresenter, y ser administrada de manera uniforme por contrato.

paso 1. Primero defina la interfaz pública para la especificación unificada

public interface IPresenter {
    ...
    //一些公共的接口
}
public interface IView {
     ...
    //一些公共的接口
}

paso 2. La interfaz definida debe heredar IView e IPresenter, y ser administrada por Contract

public interface LoginContract {
    interface View extends IView{
        //显示结果的接口
        void notifyLoginResult(boolean loginResult);
        void showTips(String verifyMsg);
    }

    interface Presenter extends IPresenter{
        void login(String name,String password);
    }
}

paso 3. Implementar las interfaces IView e IPresenter

public class LoginActivity extends AppCompatActivity implements IView {
    EditText inputUserName;
    EditText inputPassword;
    Button btnLogin;
    LoginPresenter presenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        inputUserName = this.findViewById(R.id.et_username);
        inputPassword = this.findViewById(R.id.et_password);
        btnLogin = this.findViewById(R.id.bt_login);
        presenter = new LoginPresenter(this);
        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.execureLogin(getEditorText(inputUserName),getEditorText(inputPassword));
            }
        });
    }

    private String getEditorText(EditText et) {
        return et.getText().toString();
    }

    public void notifyLoginResult(boolean loginResult) {
        if (loginResult) {
            showTips("登录成功");
        } else {
            showTips("登录失败");
        }
    }

    public void showTips(String verifyMsg) {
        Toast.makeText(LoginActivity.this, verifyMsg, Toast.LENGTH_SHORT).show();
    }
}
public class LoginPresenter implements IPresenter {
    //原来的LoginActivity改为了IView
    private IView activity;
    private LoginModel model;
    private String verifyMsg;
    public LoginPresenter(LoginActivity activity) {
        this.activity = activity;
        this.model = new LoginModel();
    }
    public void execureLogin(String username,String password){
        boolean verifyBefore = verifyBeforeLogin(username,password);
        if (verifyBefore) {
             model.login(username, password, new LoginModel.OnLoginCallback() {
                 @Override
                 public void onResponse(boolean success) {
                     activity.notifyLoginResult(success);
                 }
             });
        }else {
            activity.showTips(verifyMsg);
        }
    }

    private boolean verifyBeforeLogin(String username, String password) {
        boolean isEmpty = isEmpty(username) || isEmpty(password);
        boolean isValid = isValid(username) && isValid(password);
        if (isEmpty) {
            verifyMsg = "请输入帐号或密码";
            return false;
        }
        if (isValid) {
            return true;
        }
        verifyMsg = "帐号或密码错误";
        return false;
    }

    private boolean isValid(String s) {
        return Pattern.compile("^[A-Za-z0-9]{3,20}+$").matcher(s).matches();
    }

}

3. Ventajas y desventajas del modelo MVP

Ventajas de MVP:

El modelo está completamente separado de la vista para reducir el grado de acoplamiento. Podemos modificar la vista sin afectar el modelo; podemos
usar un presentador para varias vistas sin cambiar la lógica del presentador para mejorar la reutilización del código.
La lógica se coloca en el Presentador, lo que favorece el desarrollo basado en pruebas.


Desventajas de MVP:

La mayor complejidad del código, especialmente para el desarrollo de pequeñas aplicaciones de Android, hará que el programa sea redundante.
La interacción entre la vista y el presentador será demasiado frecuente. Una vez que cambie la vista, el presentador también cambiará. 

referencia

Los pasos del framework android mvp, explicando la descomposición e implementación de la arquitectura MVP en Android - Weixin_39848347's Blog - CSDN Blog

Android: comprensión y uso sencillos del modo MVP de las notas de estudio de Android - Blog de JMW1407 - Blog de CSDN

Esta es una demostración simple que usa el modo mvp para simular el inicio de sesión del usuario. _Blog de Davide~Su-Blog de CSDN

Supongo que te gusta

Origin blog.csdn.net/weixin_43858011/article/details/124625210
Recomendado
Clasificación