您的位置:首页 > 其它

andorid 中 MVP模式 个人理解与运用(原创)

2015-08-05 12:00 120 查看

andorid 中 MVP模式 个人理解与运用(原创)

原创文章,转载请注明出处!

by–臻宇

前几天阅读了关于MVC模式和MVP模式的文章,文章链接如下:

http://www.uml.org.cn/sjms/201006244.asp

笔者觉得很有意思,于是便想尝试对MVP模式的运用,笔者为了突出MVP模式的重点“怎么将数据(data)从用户接口(view)中分离出来,以及用户接口如何与数据进行交互”简化了一些代码逻辑,望大家不要介意,这里运用的情景是登录,我将尝试着运用MVP模式对登录情景将登录界面(View)与登录逻辑(Model)进行分离,他们通过Presenter进行交互。

界面如图所示:



既然是MVP模式的运用,自然少不了M(Model),V(View),P(Presenter)这三者:

/**
* Model 主要任务是处理业务
* Created by Administrator on 2015/8/4.
*/
public interface LoginModel <T>{

/**
* 处理登录
* @param name
* @param password
* @return
*/
public T login(String name,String password);

}


/**
* 视图,只要任务在于更新视图
* Created by Administrator on 2015/8/4.
*/
public interface LoginView <T> {

public  void showPreExecute();//更新马上登录前的UI变化,比如添加缓冲条什么的。。

public void showResult(T data);//将结果更新到UI上

public void showProgress(Integer progress);//更新进度

}


/**
* 控制者 Presenter
* Created by Administrator on 2015/8/4.
*/
public class Presenter extends AsyncTask<String, Integer, String> {

//模型对象
private LoginModel<Boolean> loginModel;
//视图对象
private LoginView<String> loginView;

public Presenter(LoginView<String> loginView) {

this.loginModel = new LoginTask(); //LoginTask是LoginModel的实现类
this.loginView = loginView; //一般是Activity或者Fragment
}

@Override
protected String doInBackground(String... params)
{
//做了些逻辑处理
if(TextUtils.isEmpty(params[0]) || TextUtils.isEmpty(params[1]))
{
return  "用户名或密码不能为空";
}

if(params[0].length()<6 ||params[0].length()>32)
{
return  "用户名不合法";
}

if(params[1].length()<6 ||params[1].length()>32)
{
return  "密码长度不合法";
}

//吧啦吧啦。。。
// 比如判断网络,检查用户名类型什么之类的一大堆逻辑,
//...........

//整个登录判断逻辑走完了,接下来正式登录了

for(int i=0;i<100;i++)  //模拟更新进度
{
try
{
publishProgress(i);//
Thread.sleep(200);
}catch(InterruptedException e)
{
return "登录异常!";
}
}

Boolean result = loginModel.login(params[0], params[1]);//模拟登录处理

if(result) return "登录成功";
else    return "登录失败";
}

@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
loginView.showProgress(values[0]);//将新进度更新到UI上
}

@Override
protected void onPostExecute(final String success) {
loginView.showResult(success);//业务处理好了,更新视图
}

@Override
protected void onPreExecute() {
super.onPreExecute();

if(loginView != null)
loginView.showPreExecute();//更新登录前的UI
}
}


对于Presenter,笔者只是简单地继承于AsyncTask,目的就是为了做耗时操作,可以看到,在Presenter内部做了许多逻辑处理,如果这些代码放到Actvity中,就会导致代码可读性下降了,处理了业务逻辑后,

Presenter就简单地调用了loginModel进行业务处理,而并不关心loginModel如何处理登录,然后拿到处理结果并通过调用loginView去更新视图,而并不关心loginView如何更新视图。

而且可以很清楚地看到,loginModel与loginView并没有调用或者引用关系,也就是说二者实现了解耦,完全通过Presenter控制二者的交互,应该是符合MVP模式的思想了吧。

接下来再看看,视图与模型的具体实现类吧:

/**
* 模型的实现类 处理登录请求
* Created by Administrator on 2015/8/4.
*/
public class LoginTask implements  LoginModel<Boolean> {

String mEmail;
String mPassword;
@Override
public Boolean login(String name, String password) {
//...耗时的网络请求

//假定登录失败
Boolean result = false ;
return result;
}
}


这个很简单吧,就是做些网络请求之类的,然后返回数据!

/**
* 这里Activity实现了LoginView接口,所以充当视图,其代码很简单,就是更新视图
* 这个界面不是笔者写的,只是照搬谷歌的模板。
*/
public class LoginActivity extends Activity implements LoginView<String> {

// UI
private AutoCompleteTextView nameView;
private EditText mPasswordView;
private ProgressBar mProgressView;
private View mEmailLoginFormView;
private View mSignOutButtons;
private View mLoginFormView;

Toast toast;

Presenter presenter; //控制者
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);

nameView = (AutoCompleteTextView) findViewById(R.id.username);

mPasswordView = (EditText) findViewById(R.id.password);

Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
mEmailSignInButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
String name =nameView.getText().toString(); //从UI上获取用户输入
String psw = mPasswordView.getText().toString();

presenter = new Presenter(LoginActivity.this);//创建一个控制者
presenter.execute(name,psw); //将数据提交给presenter,让presenter去处理
}
});

mLoginFormView = findViewById(R.id.login_form);
mProgressView = (ProgressBar)findViewById(R.id.login_progress);
mEmailLoginFormView = findViewById(R.id.email_login_form);
mSignOutButtons = findViewById(R.id.plus_sign_out_buttons);
}

@Override
public void showPreExecute() {
showToast("开始请求登录");
mProgressView.setVisibility(View.VISIBLE);
}

@Override
public void showResult(String data) {
mProgressView.setVisibility(View.GONE);
showToast(data);
}

@Override
public void showProgress(Integer progress) {

mProgressView.setProgress(progress);
}

void showToast(String s)
{
if(toast!=null )toast.cancel();
toast = Toast.makeText(this,s,Toast.LENGTH_SHORT);
toast.show();
}

}


作为一个Actvity,其代码量是很少了吧。可以看到,这个Actvity只做了大致做了三件事:
1.初始化UI;
2.从UI上提取用户输入,并提交给Presenter;
3.被动地更新UI。


所以整个逻辑是很清晰的,作为一个视图,它就负责UI!其实,它也可以是Fragemnt,也可以是别的什么布局,反正就是更新UI,对不,这就是MVP模式的好处啊,改天,我想改变一下进度条的显示效果,或者登陆成后弹出个窗口之类的,可以具体定位到具体的方法里改就好,不需在一大堆逻辑与UI混杂的代码里艰涩的修改。对于Model来说,修改业务代码也是如此。

我这个demo大致就这样了,XML代码很简单,我就不贴出来了,这就是我对MVP模式的理解与运用,也许还有理解不到位的地方,希望大家指出!

另外,这个demo只是为了凸显MVP模式的优点,有些细节并没有处理好,例如使用AsyncTask导致的内存泄露的问题等,请谅解啦!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: