随着对Android开发的逐渐学习,自己的代码量也越来越多,功能也越来越复杂,虽然尽量将一些方法封装或者写成单独的根据类,但是一个项目下来自己的代码还是太杂乱,太臃肿了。而且在多人开发的时候问题更加突出,所以我认为有必要给自己的项目一个合理的架构了,这次要介绍的是MVP模式在Android开发中的应用。
首先介绍一下MVP,其中M全称呼Model,是整个APP中的数据来源,比如网络请求类以及数据库之类的;V指View,当然是指视图了,在Android中一般为Avtivity及Fragment;P
全称Presenter,负责处理Model提供的数据,方便View来显示。这样一来,整个APP的架构就非常清晰了,三个部分各司其职,这样方便了代码的维护和可读性。
下面我们用MVP架构来实现一个登录功能
首先,我们要创建三个接口,它们是整个工程的MVP接口的父类,所以它只包含最基本的方法
}
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来编写逻辑代码,所以这里只使用了一个抽象类来实现
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");
}
}
}
}
然后就可以为我们的登录模块编写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层仅提供了登录方法
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);
}
}
Presenter层负责调用Model层的登录方法并且根据结果改变UI状态
public 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("@@","登录失败");
}
});
}
}
BaseActivity在onCreat和onDestory时绑定和解绑Presenter
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:点击打开链接