github地址:https://github.com/libin7278/MPV-example 需要结合开源项目理解MVP并逐步学会使用,本开源项目正在逐步完善中
框架:用来对软件设计进行分工。 设计模式:小技巧,对具体问题提出解决方案,太高代码复用率,降低耦合度。
View层一般采用XMl文件进行界面的描述; Module则对应本地数据文件或者网络获取的数据体; Controller部分则由Activity承担; 这个框架并非我们自己完成的,而是由framework给我们搭建好并提供给我们。
解除了View和Module的耦合,同时又带来了良好的可扩展性,可测试性。 使用MVP的好处:UI可能随时改变,如果业务逻辑耦合在View中,UI修改会导致我们重新抽离View中的业务逻辑。MVP刚好帮我们完成了逻辑抽离。
(1)MVC中是允许Model和View进行交互的,而MVP中很明显,Model与View之间的交互由Presenter完成。 (2)还有一点就是Presenter与View之间的交互是通过接口的。 首先看一下实现了MVP的Activity出来的效果,这是一个最简单的用户名登录
MVC特点 1.用户可以向View发送指令,再由View直接要求Modle改变状态 2.用户可以直接向Controller发送指令,再由Controller发送View 3.Controller起到事路由的作用,同时业务逻辑都部署在Controller
MVVM特点 View和Model进行双向绑定,两者之间有一方发生变化则会反映到另一方上。ViewModle要做的只是业务逻辑处理,以及修改View或者Modle的状态。
MVP特点 View更新通过Presenter,View和Modle不直接联系
package com.mvp.libin.mvp_example;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.mvp.libin.mvp_example.base.MVPBaseActivity;
import com.mvp.libin.mvp_example.bean.User;
import com.mvp.libin.mvp_example.presenter.UserLoginPresenterB;
import com.mvp.libin.mvp_example.view.IViewUserLogin;
/**
* Created by libin on 16/11/9.
*/
public class ActivityBUserLogin extends MVPBaseActivity<IViewUserLogin,UserLoginPresenterB>implements IViewUserLogin {
private EditText et_usernam,et_userpassword;
private ProgressBar pb;
private Button btn_login,btn_clear;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
findViewById();
//登录
btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.login();
}
});
//清除
btn_clear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.clear();
}
});
}
@Override
protected UserLoginPresenterB createPresenter() {
return new UserLoginPresenterB(this);
}
private void findViewById() {
et_userpassword = (EditText) findViewById(R.id.et_userpassword);
et_usernam = (EditText) findViewById(R.id.et_usernam);
btn_login = (Button) findViewById(R.id.btn_login);
btn_clear = (Button) findViewById(R.id.btn_clear);
pb = (ProgressBar) findViewById(R.id.pb);
}
@Override
public String getUserName() {
return et_usernam.getText().toString();
}
@Override
public String getPassword() {
return et_userpassword.getText().toString();
}
@Override
public void clearUserName() {
et_usernam.setText("");
}
@Override
public void clearPassword() {
et_userpassword.setText("");
}
@Override
public void showLoading() {
pb.setVisibility(View.VISIBLE);
}
@Override
public void hideLoading() {
pb.setVisibility(View.INVISIBLE);
}
@Override
public void toMainActivity(User user) {
Toast.makeText(this, user.getUsername() + " login success , to MainActivity", Toast.LENGTH_SHORT).show();
}
@Override
public void showFailedError() {
Toast.makeText(this, " login failed ", Toast.LENGTH_SHORT).show();
}
}
首先考虑一下View 我们这个登录都需要啥? 然后定义出所有需要的方法
package com.mvp.libin.mvp_example.view;
import com.mvp.libin.mvp_example.bean.User;
/**
* Created by libin on 16/11/8.
*/
public interface IViewUserLogin {
String getUserName();
String getPassword();
void clearUserName();
void clearPassword();
void showLoading();
void hideLoading();
void toMainActivity(User user);
void showFailedError();
}
实现模型所需要的接口
public interface IUserModel {
public void login(String username, String password, OnLoginListener loginListener);
}
实现模型所需要的接口
public interface OnLoginListener {
void loginSuccess(User user);
void loginFailed();
}
具体的业务在module完成
public class UserModel implements IUserModel {
@Override
public void login(final String username, final String password, final OnLoginListener loginListener) {
//模拟子线程耗时操作
new Thread()
{
@Override
public void run()
{
try
{
Thread.sleep(2000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
//模拟登录成功
if ("123".equals(username) && "123".equals(password))
{
User user = new User();
user.setUsername(username);
user.setPassword(password);
loginListener.loginSuccess(user);
} else
{
loginListener.loginFailed();
}
}
}.start();
}
}
将View和modle关联到一起
public class UserLoginPresenterB extends BasePresenter<IViewUserLogin> {
private IUserModel userBiz;
private IViewUserLogin userLoginView;
private Handler mHandler = new Handler();
public UserLoginPresenterB(IViewUserLogin userLoginView)
{
this.userLoginView = userLoginView;
this.userBiz = new UserModel();
}
public void login()
{
userLoginView.showLoading();
userBiz.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.clearUserName();
userLoginView.clearPassword();
}
}
接下来我们来看一下基类的实现,之所以要用弱引用,是因为Presenter经常执行一些耗时的操作,而presenter持有Activity的强引用,如果在请求结束之前Activity被销毁,网络请求还没有返回,导致presenter一直持有activity的对象,使得activity对象无法被回收,此时发生内存泄漏。
package com.mvp.libin.mvp_example.base;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
/**
* Created by libin on 16/11/8.
*/
public class BasePresenter<T> {
protected Reference<T> mViewRef; //View接口类型的弱引用
/**
* 建立关联
* @param view
*/
public void attachView(T view){
mViewRef = new WeakReference<T>(view);
}
/**
* 获取View
* @return
*/
protected T getView(){
return mViewRef.get();
}
/**
* 判断是否与View建立关联
* @return
*/
public boolean isViewAttach(){
return mViewRef != null && mViewRef.get() != null;
}
/**
* 解除关联
*/
public void detechView(){
if(mViewRef != null){
mViewRef.clear();
mViewRef = null;
}
}
}
public abstract class MVPBaseActivity<V,T extends BasePresenter<V>> extends Activity{
protected T mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = createPresenter(); //创建Presenter
mPresenter.attachView((V) this); //View与Presenter建立关联
}
@Override
protected void onDestroy() {
super.onDestroy();
mPresenter.detechView(); //解除关联
}
protected abstract T createPresenter();
}