您的位置:首页 > 移动开发 > Android开发

Android进阶 MVP设计模式实例

2016-08-11 16:53 549 查看

Android之MVP设计模式实例

MVP(Model View Presenter)的设计模式是从MVC中演化而来的,主要作用是能够:

划分模块职责,

降低模块耦合

易测试,提高代码复用

Model:数据:负责数据的检索

View: 视图:负责视图的绘制,和用户的交互

presenter: 控制器:负责在Model和View之间交互,负责两者业务的逻辑处理

与MVC的区别:

在MVC中,在Controller中,有View和Model的部分处理逻辑,在View处理时间的过程中,也有Model操作的过程,

该模式看起来模式简单,层级关系不多,而且代码量少,但是大部分逻辑都杂糅到了一起,

在测试和调试的过程中较之MVP而言很不方便

在MVC中,数据,控制器,视图之间互相操作的关系是这样的:



而在MVP中,presenter单线操作数据Model部分的数据,

同样的presenter也是单线的操作视图View模块的东西,但是中间是是通过调用接口的方式,

当View界面和数据有交互的时候,再通过接口调用Presenter,再由Presenter调用Model来进行数据的改变

在MVP中,数据,控制器,视图之间相互操作的关系是这样的:



Android代码示例

简单的演示一个登陆操作的界面,用户输入用户名密码,然后模拟操作访问服务器验证用户名密码的操作,此过程显示进度条,登陆成功之后显示成功界面,失败提示失败信息

简单的看一下界面:

activity_user_login.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/username"
android:textSize="18sp"
android:layout_alignParentLeft="true"
android:layout_marginTop="20dp"
android:id="@+id/id_tv_username"/>
<EditText
android:layout_width="170dp"
android:layout_height="40dp"
android:id="@+id/id_et_username"
android:layout_alignParentRight="true"
android:layout_marginRight="20dp"
android:text="username"
android:layout_alignBottom="@+id/id_tv_username" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/passwprd"
android:textSize="18sp"
android:layout_alignParentLeft="true"
android:layout_marginTop="80dp"
android:id="@+id/id_tv_password"/>
<EditText
android:layout_width="170dp"
android:layout_height="40dp"
android:id="@+id/id_et_password"
android:layout_alignBottom="@id/id_tv_password"
android:layout_alignParentRight="true"
android:layout_marginRight="20dp"
android:text="password" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/id_btn_login"
android:text="Login"

android:layout_below="@+id/id_et_password"
android:layout_alignEnd="@+id/id_tv_username"
android:layout_marginTop="35dp" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/id_btn_clear"
android:text="Clear"
android:layout_alignTop="@+id/id_btn_login"
android:layout_alignEnd="@+id/id_et_password"
android:layout_marginEnd="24dp" />

<ProgressBar
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/id_progressbar"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:visibility="invisible"/>
</RelativeLayout>


界面效果如下:



程序运行结果预览:



界面写好之后,开始分析该程序的数据和功能:

首先,需要有一个JavaBean对象User,保存username 和password字段

需要String类型的username和password

package com.jishihuitong.mvpdemo.bean;

/**
* Created by hss on 2016/8/2.
*/
public class User {
private String username;
private String password;

public String getUsername() {
return username;
}

public String getPassword() {
return password;
}

public void setUsername(String username) {
this.username = username;
}

public void setPassword(String password) {
this.password = password;
}
}


然后根据视图,肯定要有一个login的方法,在MVP中presenter操作model和view的过程都是使用接口的,所以要有一个IUserModel和UserModelImpl继续完成

IUserModel类

package com.jishihuitong.mvpdemo.model;

/**
* Created by hss on 2016/8/2.
*/
public interface IUserModel {

/**
* 登录数据模块的操作
* @param username 用户名
* @param password 密码
* @param onLoginListener 登录监听
*/
public void login(String username,String password,OnLoginListener onLoginListener);
}


IUserModel实现类

package com.jishihuitong.mvpdemo.model;

import com.jishihuitong.mvpdemo.bean.User;

/**
* Created by hss on 2016/8/2.
*/
public class UserModelImpl implements IUserModel {
@Override
public void login(final String username, final String password, final OnLoginListener onLoginListener) {
new Thread(){
@Override
public void run() {
try {
//模拟从网络加载数据,需要时间
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if("username".equals(username) && "password".equals(password)){
User user = new User();
user.setUsername(username);
user.setPassword(password);
onLoginListener.loginSuccess(user);
}else{
onLoginListener.loginFailed();
}
}
}.start();
}
}


登录成功或者失败的监听

package com.jishihuitong.mvpdemo.model;

import com.jishihuitong.mvpdemo.bean.User;

/**
* Created by hss on 2016/8/2.
*/
public interface OnLoginListener {
/**
* 登录成功
* @param user user对象
*/
public void loginSuccess(User user);

/**
* 登录失败
*/
public void loginFailed();
}


View层,上面说到,MVP设计模式中,调用View层的方法都是通过接口调用的,

所以我们需要显示定义一个View的接口ILoginVeiw,在该接口中需要有什么方法呢?

首先需要

getUsername();
getPassword();


清空输入框内容的方法

clearUsername();
clearPassword();


登录成功和登录失败的方法

toMainActivity(User user);
showFailedError();


显示进度和隐藏进度的方法

showLoading();
hideLoading();


所以综合上述表述,写出来的ILoginView接口应该是这样的:

package com.jishihuitong.mvpdemo.view;

import com.jishihuitong.mvpdemo.bean.User;

/**
* Created by hss on 2016/8/2.
*/
public interface IUserLoginView {
/**
* View层接口获取用户名的方法
* @return 输入的用户名
*/
public String getUserName();

/**
* View层接口获取密码的方法
* @return 输入的密码
*/
public String getPassword();

/**
* View层清除用户名
*/
public void clearUserName();

/**
* View层清除密码的方法
*/
public void clearPassword();

/**
* View层登录成功的方法
* @param user user对象
*/
public void toMainActivity(User user);

/**
* View层显示登录失败的方法
*/
public void showFailedError();

/**
* View层显示进度条的方法
*/
public void showLoading();

/**
* View层隐藏进度条的方法
*/
public void hideLoading();
}


而加载布局的一个类显然就是View层的了,该类要实现ILoginView接口,并且实现里面的方法:

然后登录操作,需要使用present来执行,

UserLoginActivity.java

package com.jishihuitong.mvpdemo.view;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.jishihuitong.mvpdemo.R;
import com.jishihuitong.mvpdemo.bean.User;
import com.jishihuitong.mvpdemo.presenter.UserLoginPresenter;

/**
* 登录界面主activity IView的实现类,
*/
public class UserLoginActivity extends AppCompatActivity implements IUserLoginView {

private EditText id_et_username;
private EditText id_et_password;
private Button id_btn_login;
private Button id_btn_clear;
private UserLoginPresenter mUserLoginPrestener = new UserLoginPresenter(this);
private ProgressBar id_progressbar;

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

/**
* 初始化控件
*/
private void initView() {
id_et_username = (EditText) findViewById(R.id.id_et_username);
id_et_password = (EditText) findViewById(R.id.id_et_password);
id_btn_login = (Button) findViewById(R.id.id_btn_login);
id_btn_clear = (Button) findViewById(R.id.id_btn_clear);
id_progressbar = (ProgressBar) findViewById(R.id.id_progressbar);

id_btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//              presenter控制逻辑 登录操作
mUserLoginPrestener.login();
}
});

id_btn_clear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mUserLoginPrestener.clear();
}
});
}

@Override
public String getUserName() {
return id_et_username.getText().toString();
}

@Override
public String getPassword() {
return id_et_password.getText().toString();
}

@Override
public void clearUserName() {
id_et_username.setText("");
}

@Override
public void clearPassword() {
id_et_password.setText("");
}

@Override
public void toMainActivity(User user) {
Toast.makeText(getApplicationContext(),getUserName()+"登录成功",Toast.LENGTH_SHORT).show();
}

@Override
public void showFailedError() {
Toast.makeText(getApplicationContext(),getUserName()+"登录失败",Toast.LENGTH_SHORT).show();
}

@Override
public void showLoading() {
id_progressbar.setVisibility(View.VISIBLE);
}

@Override
public void hideLoading() {
id_progressbar.setVisibility(View.INVISIBLE);
}
}


UserLoginPresenter.java

package com.jishihuitong.mvpdemo.presenter;

import android.os.Handler;

import com.jishihuitong.mvpdemo.bean.User;
import com.jishihuitong.mvpdemo.model.IUserModel;
import com.jishihuitong.mvpdemo.model.OnLoginListener;
import com.jishihuitong.mvpdemo.model.UserModelImpl;
import com.jishihuitong.mvpdemo.view.IUserLoginView;

/**
* Created by hss on 2016/8/2.
*/
public class UserLoginPresenter {
private IUserModel userModel;
private IUserLoginView userLoginView;
private Handler mHandler = new Handler() {
};

public UserLoginPresenter(IUserLoginView userLoginView) {
this.userModel = new UserModelImpl();
this.userLoginView = userLoginView;
}

/**
* 登录操作
*/
public void login() {
//      设置进度条可见
userLoginView.showLoading();
//数据控制器控制model操作登录
userModel.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener() {
@Override
public void loginSuccess(final User user) {
//需要在UI线程执行
mHandler.post(new Runnable() {
@Override
public void run() {
userLoginView.toMainActivity(user);
userLoginView.hideLoading();
}
});
}

@Override
public void loginFailed() {
//需要在UI线程执行
mHandler.post(new Runnable() {
@Override
public void run() {
userLoginView.showFailedError();
userLoginView.hideLoading();
}
});
}
});
}

/**
* 清除所有数据的方法
*/
public void clear() {
userLoginView.clearPassword();
userLoginView.clearUserName();
}
}


总体来说,虽然说代码的层次增加了,代码量也增加了,但是仔细看看,是不是代码感觉特别明朗,层次感特别清晰呢,该模式主要适用于数据和view交互比较多的模块,

MVP时下很火,所以在此了解学习一下,有不足的地方,欢迎指正。

点击下载代码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android mvp 设计模式