随着对Android开发的逐渐学习,自己的代码量也越来越多,功能也越来越复杂,虽然尽量将一些方法封装或者写成单独的根据类,但是一个项目下来自己的代码还是太杂乱,太臃肿了。而且在多人开发的时候问题更加突出,所以我认为有必要给自己的项目一个合理的架构了,这次要介绍的是MVP模式在Android开发中的应用。
首先介绍一下MVP,其中M全称呼Model,是整个APP中的数据来源,比如网络请求类以及数据库之类的;V指View,当然是指视图了,在Android中一般为Avtivity及Fragment;P
全称Presenter,负责处理Model提供的数据,方便View来显示。这样一来,整个APP的架构就非常清晰了,三个部分各司其职,这样方便了代码的维护和可读性。
下面我们用MVP架构来实现一个登录功能
首先,我们要创建三个接口,它们是整个工程的MVP接口的父类,所以它只包含最基本的方法
public interface MvpView {
}
public interface MvpPresenter<V extends MvpView> {
//绑定View
public void attachView(V view);
//解除绑定
public void detachView();
}
public interface MvpModel {
}
可以看到,只有MvpPresenter里有两个方法,它们用来绑定和解绑view,至于MvpView和MvpModel接口如果工程没有什么能够抽象出来的方法就可以不写
接下来为我们的登录模块创建接口
public interface LoginView<M> extends MvpView {
//显示加载中的视图
public void showLoading(boolean pullToRefresh);
//显示登录人信息
public void showInformation(User user);
//登录失败提示
public void loginFail(String err);
}
Presenter中需要根据不同的View和不同的Model来编写逻辑代码,所以这里只使用了一个抽象类来实现
attachView(V view);
detachView();
public abstract class MvpBasePresenter<V extends MvpView> implements MvpPresenter<V>{ private V view; @Override public void attachView(V view) { this.view = view; Log.d("@@MVP:","view attached"); } @Override public void detachView() { if (view !=null){ view = null; Log.d("@@MVP:","view deattached"); } } }
public class MvpBaseModel implements MvpModel {
}
然后就可以为我们的登录模块编写MVP的代码了,这里使用了一个User实体类和UserBiz登录工具类,还创建了一个登录状态的回调接口OnLoginListener和登录方法接口UserLogin
public interface UserLogin { public void login(String username, String password, OnLoginListener loginListener); }
public interface OnLoginListener { void loginSuccess(User user); void loginFailed(); }
public class User { private String username ; private String password ; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
public class UserBiz implements UserLogin { @Override public void login(final String username, final String password, final OnLoginListener loginListener) { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } if (username.equals("327570221") && password.equals("123")) { User user = new User(); user.setUsername(username); user.setPassword(password); loginListener.loginSuccess(user); }else { loginListener.loginFailed(); } } }).start(); } }
下面是登录模块的MVP代码
Model层仅提供了登录方法
Presenter层负责调用Model层的登录方法并且根据结果改变UI状态public class LoginModel extends MvpBaseModel { Context mContext; public LoginModel(Context mContext){ this.mContext=mContext; } public void Login(String name, String psd, OnLoginListener listener){ UserBiz userBiz=new UserBiz(); userBiz.login(name,psd,listener); } }
BaseActivity在onCreat和onDestory时绑定和解绑Presenterpublic class LoginPresenter extends MvpBasePresenter { private LoginModel loginModel; Context mContext; LoginView loginView; Handler handler; public LoginPresenter(Context mContext,LoginView v){ this.mContext=mContext; loginModel=new LoginModel(mContext); loginView= v; handler=new Handler(); } public void Login(String name, String psd){ loginView.showLoading(true); loginModel.Login(name, psd, new OnLoginListener() { @Override public void loginSuccess(final User user) { handler.post(new Runnable() { @Override public void run() { loginView.showInformation(user); loginView.showLoading(false); } }); Log.d("@@","登录成功"); } @Override public void loginFailed() { handler.post(new Runnable() { @Override public void run() { loginView.loginFail("登录失败"); loginView.showLoading(false); } }); Log.d("@@","登录失败"); } }); } }
public abstract class BaseActivity<P extends MvpBasePresenter> extends AppCompatActivity implements MvpView { P presenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); presenter = bindPresenter(); Log.d("@@","onCreated"); //我的presenter中介我是不是管理View---关联 if (presenter != null){ Log.d("@@","attachView"); presenter.attachView(this); } } //具体的实现我不知道,我给别人实现 public abstract P bindPresenter(); @Override protected void onDestroy() { super.onDestroy(); Log.d("@@","onDestory"); //Activity销毁的时候---解除绑定 if (presenter != null){ Log.d("@@","detachView"); presenter.detachView(); } } }
View层仅仅实现了改变View的方法,是不是很清爽public class MvpLoginActivity extends BaseActivity implements LoginView{ EditText userName; EditText passWord; Button loginBtn; TextView infoTv; ProgressBar progressBar; LoginPresenter presenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_mvp_login); userName= (EditText) findViewById(R.id.editText); passWord= (EditText) findViewById(R.id.editText2); loginBtn= (Button) findViewById(R.id.login); loginBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String name=userName.getText().toString(); String pass=passWord.getText().toString(); Log.d("@@mvpActivity",name+pass); presenter.Login(name,pass); } }); infoTv= (TextView) findViewById(R.id.textView); progressBar= (ProgressBar) findViewById(R.id.progressBar); progressBar.setVisibility(View.GONE); } @Override public MvpBasePresenter bindPresenter() { presenter=new LoginPresenter(MvpLoginActivity.this,this); return presenter; } @Override public void showLoading(boolean pullToRefresh) { if (pullToRefresh){ progressBar.setVisibility(View.VISIBLE);} else { progressBar.setVisibility(View.GONE); } } @Override public void showInformation(User user) { String s=user.getUsername()+"\n"+user.getPassword(); infoTv.setText(s); } @Override public void loginFail(String err) { infoTv.setText(err); } }
这样我们的demo就完成了,需要的可以下载我的demo:点击打开链接