天天看点

Android学习笔记之MVP架构初体验

随着对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:点击打开链接