Android开发之MVP模式

前言:Android开发中有很多的设计模式,MVP模式无疑是现在最流行的模式之一。MVP模式有效的降低了项目的复杂性及耦合性,view与model间完全解耦,通过presenter作为中间的连接纽带,降低了view的复杂性及view与model耦合程度,使的项目逻辑更加清晰,方便后期的修改与维护。

MVP:Model--View--Presenter

model:用于数据的处理,如请求网络数据等

view:用于将presenter传递的数据在UI中展示

presenter:将model获取的数据传递给view,是view与model联系的中间桥梁

注:文中有用到Retrofit2+Rxjava2+Okhttp3实现网络数据请求相关的知识,这一篇文章 Android网络请求Retrofit2+Rxjava2+Okhttp3的简单封装中有详细介绍。

1.Model

(1)定义model基类接口

/**
 * Created by ruancw on 2018/5/22.
 * model接口基类
 */

public interface IBaseModel {

    <T>Disposable getObservable(Observable<HttpResponse<T>> observable, String tag);
    //网络请求接口回调
    interface IOnRequestListener<T>{
        void onRequestSuccess(HttpResponse<T> tHttpResponse, String tag);
        void onRequestFail(Throwable throwable);
    }
}

(2)定义model实现类

/**
 * Created by ruancw on 2018/5/22.
 * 通用model实现类
 */

public class CommonModelImpl implements IBaseModel {
    private IOnRequestListener onRequestListener;

    public CommonModelImpl(IOnRequestListener onRequestListener) {
        this.onRequestListener = onRequestListener;
    }

    @Override
    public <T> Disposable getObservable(Observable<HttpResponse<T>> observable, String tag) {
        return DisposableUtils.getDisposable(observable,tag,onRequestListener);
    }
}

2.View

定义view接口类

/**
 * Created by ruancw on 2018/5/22.
 * view基类接口
 */

public interface IBaseView {
    //显示默认的进度框
    void showProgress();
    //显示可设置提示信息的进度框
    void showProgress(String message);
    //隐藏进度框
    void hideProgress();
    //网络请求数据成功后返回数据的方法
    void onSuccess(HttpResponse httpResponse, String tag);
    //网络请求失败的方法
    void onFailed(Throwable throwable);
}

3.Presenter

(1)定义presenter的基类

/**
 * Created by ruancw on 2018/5/22.
 * presenter基类
 */

public class BasePresenter implements IBaseModel.IOnRequestListener {
    //view接口
    protected IBaseView mView;
    //model接口实现类
    protected CommonModelImpl mModel;
    //Rxjava中的类
    private CompositeDisposable mCompositeDisposable;

    /**
     * 绑定view
     * @param mView
     */
    public void attach(IBaseView mView){
        this.mView=mView;
        mModel=new CommonModelImpl(this);
    }

    /**
     * 解绑view
     */
    public void detach(){
        if (mView!=null){
            mView=null;
        }
    }

    /**
     * 反注册rxjava
     */
    public void unSubscribe(){
        if (mCompositeDisposable != null) {
            mCompositeDisposable.dispose();
        }
    }

    /**
     * 注册rxjava
     * @param disposable
     */
    public void addSubscription(Disposable disposable) {//rxjava进行注册
        if (mCompositeDisposable == null) {
            mCompositeDisposable= new CompositeDisposable();
        }
        mCompositeDisposable.add(disposable);
    }

    @Override
    public void onRequestSuccess(HttpResponse httpResponse, String tag) {
        if (mView!=null){
            mView.hideProgress();
            mView.onSuccess(httpResponse,tag);
        }
    }

    @Override
    public void onRequestFail(Throwable throwable) {
        if (mView!=null){
            mView.hideProgress();
            mView.onFailed(throwable);
        }
    }
}
(2)继承基类BasePresenter(以登录为例)

/**
 * Created by ruancw on 2018/5/23.
 * 登录的presenter实现类
 */

public class LoginPresenterImpl extends BasePresenter {
    public void login(String url, LinkedHashMap<String, String> paramsMap,String tag){
        mView.showProgress("正在登录");
        addSubscription(mModel.getObservable(HttpApiService.getInstance().getRemoteData(url,paramsMap),tag));
    }
}

注:直接定义的LoginPresenter的实现类,没有定义ILoginPresenter接口

4.模块中使用

(1)定义Activity基类

public abstract class BaseMvpActivity<B extends BasePresenter> extends BaseActivity {

    public B mPresenter;

    @Override
    protected void beforeSetContentView() {
        mPresenter=initPresenter();
        mPresenter.attach(this);
    }

    protected abstract B initPresenter();

    @Override
    protected void onDestroy() {
        mPresenter.detach();
        //mPresenter.unSubscribe();
        super.onDestroy();
    }
}

(2)LoginActivity继承BaseMvpActivity

public class LoginActivity extends BaseMvpActivity<LoginPresenterImpl> {
    @BindView(R.id.btn_login)
    Button btnLogin;
    @BindView(R.id.et_account)
    ClearEditText etAccount;
    @BindView(R.id.et_password)
    PasswordView etPassword;
    private int userType=1;
    private UserBean userBean;
    private boolean autoLogin;


    @Override
    protected boolean hasHeadTitle() {
        return false;
    }

    @Override
    protected LoginPresenterImpl initPresenter() {
        return new LoginPresenterImpl();
    }

    @Override
    protected int getLayoutId() {
        return R.layout.activity_login;
    }

    @Override
    protected void initView() {
        //获取上一次填写的用手机号与密码
        userBean=SharePreferencesUtil.getInstance().getUserBean();
        if (this.getIntent() != null && this.getIntent().getExtras() != null && this.getIntent().getExtras().containsKey("username")) {
            String username = this.getIntent().getExtras().getString("username");
            etAccount.setText(username);
        } else {
            if (userBean != null) {
                etAccount.setText(userBean.getAccount());
                etPassword.setContent(userBean.getPassword());
            }
        }
        //判断是否是自动登录
        autoLogin=SharePreferencesUtil.getInstance().getBoolean("AUTO_LOGIN");
        if (autoLogin){
            //自动登录
            login();
        }
    }

    /**
     * 登录的方法
     */
    private void login() {
        etPassword.clearFocus();
        //系统的输入管理器
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.showSoftInput(etPassword, InputMethodManager.SHOW_FORCED);
        imm.hideSoftInputFromWindow(etPassword.getWindowToken(), 0);
        if (TextUtils.isEmpty(etAccount.getText().toString().trim())) {
            //etAccount.setError("手机号不能为空");
            UIUtil.toast("手机号不能为空");
        } else if (TextUtils.isEmpty(etPassword.getContent().trim())) {
            //etAccount.setError("手机号不能为空");
            UIUtil.toast("密码不能为空");
        } else {
            LinkedHashMap<String, String> paramsMap = new LinkedHashMap<>();
            paramsMap.put("loginName", etAccount.getText().toString().trim());
            paramsMap.put("password", etPassword.getContent().trim());
            paramsMap.put("userType", userType + "");
            mPresenter.login(ApiConstant.LOGIN, paramsMap, "tag");
        }
    }

    @OnClick(R.id.btn_login)
    public void onViewClicked() {
        //点击的动画效果
        CommonUtil.animateClickView(btnLogin, new CommonUtil.ClickAnimation() {
            @Override
            public void onClick(View v) {
                login();
            }
        });

    }

    @Override
    public void onSuccess(HttpResponse httpResponse, String tag) {
        int code = httpResponse.getStatus();
        Log.i("rcw", "httpResponse=" + httpResponse);
        Log.i("rcw", "code=" + httpResponse.getStatus());
        Log.i("rcw", "data=" + httpResponse.getData());
        if (code == 200) {
            userBean=new UserBean();
            userBean.setAccount(etAccount.getText().toString().trim());
            userBean.setPassword(etPassword.getContent().trim());
            userBean.setUsertype(userType);
            SharePreferencesUtil.getInstance().saveUserBean(userBean);

            String datas = new Gson().toJson(httpResponse.getData());
            LoginBean loginBean = new Gson().fromJson(datas, LoginBean.class);
            SharePreferencesUtil.getInstance().saveLoginBean(loginBean);
            Log.i("rcw", "getDeptName=" + loginBean.getDeptName());
            startActivity(new Intent(this, MainActivity.class));
            finish();
            UIUtil.toast("登录成功");
        } else if (code == 402) {
            exitToLogin(this);
        } else {
            UIUtil.toast(httpResponse.getMessage());
        }

    }
总结:MVP模式使得View与Model间不能直接交互,通过中间纽带Presenter实现间接联系,降低了View与Model间的耦合。MVP模式虽好,但如果项目页面相对简单,可以直接使用MVC模式实现。

如有任何问题,欢迎评论及留言,不胜感激,谢谢!!!


猜你喜欢

转载自blog.csdn.net/ruancw/article/details/80622457