Android MVP 框架搭建

前言
本文主要根据自身项目的使用和对MVP的理解,搭建符合自身项目情况的MVP架构。

关于MVP
M(Model)负责数据的请求,解析,过滤等数据操作。
V(View)负责处理UI,通常以Activity Fragment的形式出现。
P(Presenter)View Model中间件,交互的桥梁。
MVP的好处

分离了UI逻辑和业务逻辑,降低了耦合。
Activity只处理UI相关操作,代码变得更加简洁。
UI逻辑和业务逻辑抽象到接口中,方便阅读及维护。
把业务逻辑抽到Presenter中去,避免复杂业务逻辑造成的内存泄漏。
具体实现
1.view

IView:一般情况下,做数据请求都有显示加载框、请求成功、请求失败等操作,我们把这些共有的功能封装到IView中。

public interface IView {
    /**
     * 显示加载框
     */
    void showLoading();

    /**
     * 隐藏加载框
     */
    void dismissLoading();

    /**
     * 网络请求失败
     *
     * @param ex   异常信息
     * @param code 错误码
     * @param msg  错误信息
     */
    void onFail(Throwable ex, String code, String msg);

    /**
     * 网络错误
     */
    void onNetError();

}

2.Presenter

IPresenter:为了避免持有View的Presenter做耗时操作而引起的内存泄漏,我们的Presenter应该和宿主Activity/Fragment生命周期绑定。

public interface IPresenter<T extends IView> {
    /**
     * 绑定view
     * @param view view
     */
    void attachView(T view);

    /**
     * 分离view
     */
    void detachView();

    /**
     * 判断view是否已经销毁
     * @return true 未销毁
     */
    boolean isViewAttach();

}

BasePresenter:抽象的persenter业务处理层。关联抽象层view和抽象model。

public abstract class BasePresenter<T extends IView, K extends IModel> implements IPresenter<T> {
    protected K mModel;
    private WeakReference<T> weakReference;

    @Override
    public void attachView(T view) {
        // 使用弱引用持有view对象,防止内存泄漏
        weakReference = new WeakReference<>(view);
        if (this.mModel == null) {
            this.mModel = createModule();
        }
    }

    @Override
    public void detachView() {
        if (isViewAttach()) {
            weakReference.clear();
            weakReference = null;
        }
        if (mModel != null) {
            mModel.unSubscribe();
            mModel = null;
        }
    }

    @Override
    public boolean isViewAttach() {
        return weakReference != null && weakReference.get() != null;
    }

    protected T getView() {
        return weakReference.get();
    }

    protected void showLoading() {
        if (isViewAttach()) {
            getView().showLoading();
        }
    }

    protected void onFail(Throwable ex, String code, String msg) {
        if (isViewAttach()) {
            getView().onFail(ex, code, msg);
        }
    }

    protected void onNetError() {
        if (isViewAttach()) {
            getView().onNetError();
        }
    }

    protected void dismissLoading() {
        if (isViewAttach()) {
            getView().dismissLoading();
        }
    }

    /**
     * 由外部创建 module
     *
     * @return module
     */
    protected abstract K createModule();

}

3.model

IModel:由于项目使用Rxjava+Retrofit2.0+Okhttp,所以我在model层对Rxjava进行绑定和解绑,防止内存泄漏。

public interface IModel {
    void unSubscribe();

    void addSubscribe(Subscription subscription);
}

BaseModel:实现对Rxjava绑定和解绑,初始化ApiService。

public class BaseModel implements IModel {
    protected ApiService mApi;
    private CompositeSubscription mCompositeSubscription;

    public BaseModel() {
        this.mApi = RetrofitHelper.getInstance().createApiService(AppConstants.BASE_SERVER_IP);
    }

    @Override
    public void unSubscribe() {
        if (mCompositeSubscription != null && !mCompositeSubscription.isUnsubscribed()) {
            mCompositeSubscription.clear();
            mCompositeSubscription.unsubscribe();
        }
    }

    @Override
    public void addSubscribe(Subscription subscription) {
        if (mCompositeSubscription == null) {
            mCompositeSubscription = new CompositeSubscription();
        }
        mCompositeSubscription.add(subscription);
    }
}

4.BaseMvpActivity基类
通过泛型规定Presenter,并且暴露抽象方法createPresenter()给子类来创建Presenter,基类实现IView中的公共方法,减少子类代码的冗余。至于BaseMvpActivity功能根据项目业务需求进行封装。

public abstract class BaseMvpActivity<P extends BasePresenter> extends AppCompatActivity implements IView {
    protected P mPresenter;
    private Unbinder unbinder;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutId());
        unbinder = ButterKnife.bind(this);
        // 初始化Presenter
        initPresenter();
    }

    private void initPresenter() {
        mPresenter = createPresenter();
        // 完成Presenter和view的绑定
        if (mPresenter != null) {
            mPresenter.attachView(this);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 将Presenter和view解绑
        if (mPresenter != null) {
            mPresenter.detachView();
            mPresenter = null;
        }
        // 解绑ButterKnife
        if (unbinder != null) {
            unbinder.unbind();
        }      
    }

    @Override
    public void showLoading() {
       // 这里实现自己的加载弹框
    }

    @Override
    public void dismissLoading() {
       // 取消弹框
    }

    @Override
    public void onFail(Throwable ex, String code, String msg) {
        // 基础的网络请求失败处理
    }

    @Override
    public void onNetError() {
        // 网络错误处理
    }

    /**
     * 页面初始化数据
     */
    protected void initData() {

    }

    /**
     * 创建Presenter
     *
     * @return Presenter
     */
    protected abstract P createPresenter();

    /**
     * 获取当前activity的id
     *
     * @return 当前xml的布局res ID
     */
    protected abstract int getLayoutId();

    /**
     * 初始化view控件
     */
    protected abstract void initView();

}

使用MVP
1.契约类Contract

通过契约类来管理Model、View、Presenter的所有接口,这样使得Presenter和View有哪些功能一目了然,维护起来也方便,同时使得View与Presenter一一对应,并有效地减少类的数目。

public interface LoginContract {

    interface View extends IView {
         /**
         * 登录成功
         */
        void onLoginSuccess(UserInfo data);
         /**
         * 登录失败
         */
        void onLoginFail(Throwable ex, String code, String msg);
    }

    interface Presenter {
        void login(String phone, String password);
    }

    interface Model extends IModel {
        /**
         * 登录
         *
         * @param map 用户登陆信息
         * @param subscriber 回调
         */
        void login(Map map, Subscriber subscriber);

    }

}

2.LoginPresenter

public class LoginPresenter extends BasePresenter<LoginContract.View, LoginContract.Model> implements LoginContract.Presenter {

    @Override
    protected LoginContract.Model createModule() {
        return new LoginModel();
    }

    @Override
    public void login(String phone, String password) {
        showLoading();
        Map<String, String> params = new HashMap<>();
        params.put("phone", phone);
        params.put("password", password);
        
        mModel.login(params, new BaseSubscriber<UserInfo>(new CallBackListener<UserInfo>() {
            @Override
            public void onSuccess(String code, UserInfo data) {
                dismissLoading();
                if (isViewAttach()) {
                    getView().onLoginSuccess(data);
                }
            }

            @Override
            public void onFailed(Throwable ex, String code, String msg) {
                dismissLoading();
                if (isViewAttach()) {
                    getView().onLoginFail(ex, code, msg);
                }
            }

            @Override
            public void onError() {
                onNetError();
            }
        }));
    }

}


3.LoginModel

public class LoginModel extends BaseModel implements LoginContract.Model{
    @Override
    public void login(Map map, Subscriber subscriber) {
        Subscription subscription = mApi.login(map).compose(RetrofitHelper.applySchedulers()).subscribe(subscriber);
        addSubscribe(subscription);
    }

}

4.LoginActivity

public class LoginActivity extends BaseMvpActivity<LoginPresenter> implements LoginContract.View {

    @BindView(R.id.tv_service)
    TextView tvService;
    
    private UserInfo userInfo;

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

    @Override
    protected LoginPresenter createPresenter() {
        return new LoginPresenter();
    }

    @Override
    protected void initView() {
      addHeadTitle("登陆");
    }

    @OnClick({R.id.login, R.id.register})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.login:
                   mPresenter.login(phone,password);
                break;
            case R.id.register:
                  // 注册 
                break;
        }
        
    }

    @Override
    public void onLoginSuccess(UserInfo data) {
        // 登陆成功回调
    }

    @Override
    public void onLoginFail(Throwable ex, String code, String msg) {
        // 登陆失败回调
    }
   
}

总结
至此,MVP搭建完成。其实还有很多可以优化的地方。每个人对MVP的理解不一样,而MVP架构也并不是一成不变,适合自己项目的才是最好的。

GitHub地址:https://github.com/mingyang22/MVP_demo
————————————————
版权声明:本文为CSDN博主「MingYang丶」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ym4189/article/details/86016276

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值