| 版权声明:本文为博主原创文章,未经博主允许不得转载。
1.简介
大家都知道并熟悉Mvc模式,Android原生使用也是采用Mvc的模式,但是却存在着它最大的问题就是职责不清晰,如果有人面试时问你你的项目中Mvc中C代表的是什么你肯定马上想都不想就回答代表的是controler,如果别人再问你那你的Controler和View之间的区别你会发现你把自己绕进去了很难描叙清楚,因为Mvc在Android中最大的缺陷就是它的controler和View是很难分离的整个项目也会显得耦合度太高,而且View与model之间是之间可以交互View与controler之间也是之间可以交互这样就会出现混乱。幸好有大牛研究出了MVP,MVP就是专门用来解决Mvc职责不清晰的问题,其中M还是代表的是model,V代表的是View,Presenter就充当了View与model之间交互的中间方,这样就避免了原来View可以与Activity进行交互,也可以与model进行交互,model也可以与Activity进行交互的混乱,现在MVP中View只与presenter交互,model只与presenter交互,职责清晰一目了然。
2.实例
概念上基本理清了Mvc与Mvp之间的区别现在我们就以实际代码进行详细的解释,首先我们得清楚Mvp是通过接口回调的方式进行实现的,所以UI层,model层都是需要接口实现的。
我们以一个登陆的例子来说明这个模式,因为登陆可以说是比较简单的而且可以完全覆盖我们Mvp中需要的大部分的实例。下面是登陆的图片
1.首先不管Mvc还是Mvp模式Bean肯定是不可少的。这个UserBean也就是用户登陆的实例 ,简单明了就不多说了
public class UserBean {
//账号
private String account;
//密码
private String password;
public UserBean(String account, String password) {
this.account = account;
this.password = password;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
2.然后我们需要写,model就是业务逻辑层,这里我们还是采用接口的实现方式,因为这样内部方法一目了然也方便单元测试,我们所有的业务必须在model中使用,
不要像Mvc中很多业务逻辑在Activity中直接使用而且需要View的支持这样很容易造成内存泄露,因为很多异步任务退居后台后但是还是保留了对当前Activity的引用
而Java的回收机制会在内存不足的情况下回收Activity这样引用的Activity就没有了很容易内存泄露。
//model接口
public interface ILoginBiz {
void login(String account,String password,OnLoginListener listener);
}
//model实现
public class LoginBiz implements ILoginBiz {
@Override
public void login(String account, String password, final OnLoginListener listener) {
if (!(account.equals("")&&password.equals("")))
{
//账号密码不为空允许登录,登录成功
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
listener.loginsucess();
}
}).start();
}
else
{
//账号密码为空登录失败
listener.loginFailed();
}
}
}
3.然后就是View层,Mvp中我们都是以Activity作为View使用,明显区别于Mvc,但是我们需要把Activity的View引用提供给presenter,而且在Activity中实现回调更新界面在这里回调的方法我们抽象出来成为一个接口
//里面的所有的方法都是用来更新UI
public interface ILoginView {
String getAccount();
String getPassWord();
void loginSucess();
void loginFailed();
}
有人会问不是说都是用来更新ui的方法吗为什么还有getAccount()和getPassWord()方法,很简单你想想因为你的View是在presenter中与model层进行交互的而不是在Activity中,那么你的账号密码肯定不能直接用
EdtText.getText().toString()吧,所以需要一个方法来获取到account和password。
4.最后就是presenter层了这里是用来控制View与model交互的,需要知道的是在biz的回调函数中需要使用一个handler。post(new Runnable)来更换UI的(handler.post()和handler.sendMessage()都是用来通知的),
这里的new Runable中的方法写的就是更新UI的操作也就是UI线程,别理解为了
怎么又重开了一个线程。其中View的接口回调可以让你在Activity中做一些更新的后续操作,
public class UserLoginpre {
private ILoginView view;
private ILoginBiz loginBiz;
private Handler handler=new Handler();
public UserLoginpre(ILoginView iLoginView) {
view=iLoginView;
loginBiz=new LoginBiz();
}
public void login()
{
loginBiz.login(view.getAccount(), view.getPassWord(), new OnLoginListener() {
@Override
public void loginsucess() {
//更新UI线程
handler.post(new Runnable() {
@Override
public void run() {
view.loginSucess();
}
});
}
@Override
public void loginFailed() {
handler.post(new Runnable() {
@Override
public void run() {
view.loginFailed();
}
});
}
});
}
}
有没有看到在UserLoginPre()构造函数中我们已经把View和model都给放在了presenter中了这样就是实现了View和model在presenter中交互,然后又通过回调函数实现了更新。
5.最后就是Activity中代码了就一些更新操作实现了model,View的分离。
//mvp中activity都是实现view层接口然后与presenter进行交互
public class LoginActivity extends AppCompatActivity implements ILoginView, View.OnClickListener {
private EditText edt_account;
private EditText edt_password;
private Button btn_login;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView();
setListener();
}
public void initView()
{
edt_account = (EditText) findViewById(R.id.edt_account);
edt_password = (EditText) findViewById(R.id.edt_password);
btn_login = (Button)findViewById(R.id.btn_login);
progressBar = (ProgressBar)findViewById(R.id.progress_bar);
}
public void setListener()
{
btn_login.setOnClickListener(this);
}
public void login()
{
UserLoginpre loginpre=new UserLoginpre(this);
progressBar.setVisibility(View.VISIBLE);
loginpre.login();
}
@Override
public String getAccount() {
return edt_account.getText().toString();
}
@Override
public String getPassWord() {
return edt_password.getText().toString();
}
@Override
public void loginSucess() {
progressBar.setVisibility(View.GONE);
Toast.makeText(this,"登录成功",Toast.LENGTH_SHORT).show();
}
@Override
public void loginFailed() {
progressBar.setVisibility(View.GONE);
Toast.makeText(this,"登录失败",Toast.LENGTH_SHORT).show();
}
@Override
public void onClick(View v) {
login();
}
}
3.总结
Mvc与Mvp的区别我们也说明了清楚大家应该也从代码中感觉到了区别,具体使用还是需要自己写写例子用用,那么Mvp这么好有什么缺点吗,其实还是有的从代码量可以看出来多了不少,
因为使用了大量的接口而且多了一个presenter层,UI与业务必须写成接口,但是这样也有好处,好处就是让你在写代码前一定得自己先理清楚业务逻辑,不至于像以前一样一个复杂的页面
Activity内的代码都是上千行,阅读难度大也高耦合不便于修改,而且很多可以抽出的方法都不能再其他页面使用。