安卓MVP开发模式总结

本文介绍了Android的MVP开发模式,包括概述、架构、优缺点。MVP模式通过Model、View、Presenter三层分离,降低了组件间的耦合,提高了代码复用性。然而,频繁的View和Presenter交互可能导致过度紧密的联系,需要谨慎处理。

******再度回头看看安卓的MVP开发模式的总结******

 

1. 概述

       MVP(Model - View - Presenter):即 模型 - 视图 - 协调者的简写,MVP是从经典的MVC模式中演变而来的,基本逻辑上是有相通之处。Model负责提供数据源,View负责数据的展示,Presenter负责主要业务逻辑的处理,将Model和View进行联系起来,完全把Model和View进行了彻底的分离,而Presenter与具体的View是没有直接关联的,而是通过定义好了的接口进行交互的,从而使得在变更View时候可保持Presenter的不变,即重用性。也可更好的模拟单元测试。

 

2. 架构及图解

MVP图解(图片来源于网络)

Model即模型层,负责存储,检索以及操纵数据。

View即视图层,负责绘制UI,与用户进行交互(Activity / Fragment)。

Presenter即协调者(中间者),作为View与Model之间交互的中间纽带,负责处理与用户交互的主要业务逻辑。

 

3. 优缺点

优点:

① 复杂的业务逻辑处理都在Presenter中进行处理,从而减少了Activity的臃肿。

② Model层与View层完全彻底分离,修改View层不会对Model层受到影响,降低了之间的耦合性。

③ 可将一个Presenter用于一个或多个视图,从而无需改变Presenter的业务逻辑。

④ Presenter层与View层的交互是通过接口来进行的,从而便于单元测试。

缺点:

由于对视图View的渲染都在Presenter中定义,所以视图View和Presenter之间的交互会过于频繁,视图若需要改变,一般Presenter也需要跟随着变更。

 

4. 案例说明

请求接口的数据来源于 https://www.avatardata.cn/Docs/Api/5bc6f2a4-927c-415f-80ae-8772b76c8c73

有请求次数的限制,所以需要使用的,可自行注册账号,进行测试使用。

可以使用AndroidMVP插件来生成MVP的模板或者自己动手创建。

案例①

M层

/**
 * 数据接口层.
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public interface IAphorismsAModel {

    /**
     * 请求网络获取数据列表
     *
     * @param page     页码
     * @param rows     一次请求返回多少数据
     * @param callBack 回调函数
     */
    public void getListData(int page, int rows, CallBack callBack);
}
/**
 * 数据实现层.
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public class AphorismsAModelImpl implements IAphorismsAModel {

    /**
     * 请求网络获取数据列表
     *
     * @param page     页码
     * @param rows     一次请求返回多少数据
     * @param callBack 回调函数
     */
    @Override
    public void getListData(int page, int rows, final CallBack callBack) {
        String key = "9d3ce9c83fcd4c418dce2937c29b6414";
        String param = "key=" + key + "&keyword=天才&page=" + page + "&rows=" + rows;
        String url = "http://api.avatardata.cn/MingRenMingYan/LookUp?" + param;
        OkHttpUtils.get()
                .url(url)
                .build()
                .execute(new StringCallback() {

                    @Override
                    public void onResponse(String response, int id) {
                        GsonUtils utils = GsonUtils.getInstance();
                        AphorismsEntity aphorismsEntity = utils.fromJson(response, AphorismsEntity.class);
                        if (aphorismsEntity != null) {
                            callBack.onSuccess(aphorismsEntity.getResult());
                        } else {
                            callBack.onError(response);
                        }
                    }

                    @Override
                    public void onError(Call call, Exception e, int id) {
                        callBack.onError(e.getMessage());
                    }
                });
    }
}

V层

/**
 * 视图接口.
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public interface IAphorismsAView {

    // 请求标记
    public int REQUEST_ONE = 0;
    public int REQUEST_TWO = 1;
    public int REQUEST_THREE = 2;

    // 响应标记
    public int RESPONSE_SUCCESS = 200;
    public int RESPONSE_ERROR = 404;
    public int RESPONSE_FAILURE = 500;

    public <T> T request(int requestFlag);

    /**
     * 请求返回的数据
     *
     * @param response
     * @param responseFlag
     * @param <T>
     */
    public <T> void response(T response, int responseFlag);

    /**
     * 显示网络加载框
     */
    public void showLoading();

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

    /**
     * 弹出提示
     *
     * @param msg
     */
    public void showToast(String msg);
}
/**
 * 显示名言警句.
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public class AphorismsActivity extends AppCompatActivity implements IAphorismsAView {

    private SmartRefreshLayout mSmartRefreshLayout;
    private RecyclerView rcyAphorisms;
    private LoadingDialog loadingDialog;
    private AphorismsAdapter aphorismsAdapter;
    private IAphorismsAPresenter mIAphorismsAPresenter;
    private List<AphorismsEntity.ResultBean> resultBeanList = new ArrayList<>();
    private int page = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mIAphorismsAPresenter = new AphorismsAPresenterImpl(this);
        setContentView(R.layout.activity_aphorisms);

        mSmartRefreshLayout = findViewById(R.id.refresh_layout);
        rcyAphorisms = findViewById(R.id.rcy_aphorisms);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        rcyAphorisms.setLayoutManager(layoutManager);
        rcyAphorisms.setHasFixedSize(true);
        rcyAphorisms.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
        rcyAphorisms.setItemAnimator(new DefaultItemAnimator());

        aphorismsAdapter = new AphorismsAdapter(this);
        rcyAphorisms.setAdapter(aphorismsAdapter);
        // item的点击事件
        aphorismsAdapter.setOnItemClickListener(new AphorismsAdapter.OnItemClickListener() {

            @Override
            public void onItemClick(View view, int position) {
                showToast(aphorismsAdapter.getData().get(position).getFamous_name());
            }
        });

        // 获取电影列表数据
        mIAphorismsAPresenter.getListData(1, 10);

        // 刷新数据
        mSmartRefreshLayout.setOnMultiPurposeListener(new SimpleMultiPurposeListener() {

            @Override
            public void onRefresh(@NonNull RefreshLayout refreshLayout) {
                super.onRefresh(refreshLayout);
                runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        page = 1;
                        mIAphorismsAPresenter.getListData(1, 10);
                        mSmartRefreshLayout.finishRefresh();
                    }
                });
            }

            @Override
            public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
                super.onLoadMore(refreshLayout);
                runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        mIAphorismsAPresenter.getListData(++page, 10);
                    }
                });
            }
        });
    }

    @Override
    public <T> T request(int requestFlag) {
        return null;
    }

    @Override
    public <T> void response(T response, int responseFlag) {
        if (responseFlag == IAphorismsAView.RESPONSE_SUCCESS) {
            List<AphorismsEntity.ResultBean> list = (List<AphorismsEntity.ResultBean>) response;
            if (list != null && list.size() > 0) {
                resultBeanList.addAll(list);
                aphorismsAdapter.addData(resultBeanList);
                mSmartRefreshLayout.finishLoadMore();
            } else {
                showToast("数据已加载完毕");
                // 将不会再次触发加载更多事件
                mSmartRefreshLayout.finishLoadMoreWithNoMoreData();
                mSmartRefreshLayout.resetNoMoreData();
            }
        }
    }

    @Override
    public void showLoading() {
        loadingDialog = new LoadingDialog(this);
        loadingDialog.setLoadingText("加载中...");
        loadingDialog.show();
    }

    @Override
    public void dismissLoading() {
        if (loadingDialog != null) {
            loadingDialog.close();
        }
    }

    @Override
    public void showToast(String msg) {
        Toast.makeText(this, "mvp: " + msg, Toast.LENGTH_SHORT).show();
    }
}

P层

/**
 * 逻辑接口层.
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public interface IAphorismsAPresenter {

    /**
     * 请求网络获取数据列表
     *
     * @param page 页码
     * @param rows 一次请求返回多少数据
     */
    public void getListData(int page, int rows);
}
/**
 * 逻辑实现层.
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public class AphorismsAPresenterImpl implements IAphorismsAPresenter {

    private IAphorismsAView mIAphorismsAView;
    private IAphorismsAModel mIAphorismsAModel;

    public AphorismsAPresenterImpl(IAphorismsAView aIAphorismsAView) {
        mIAphorismsAView = aIAphorismsAView;
        mIAphorismsAModel = new AphorismsAModelImpl();
    }

    /**
     * 请求网络获取数据列表
     *
     * @param page 页码
     * @param rows 一次请求返回多少数据
     */
    @Override
    public void getListData(int page, int rows) {
        if (mIAphorismsAView == null) {
            return;
        }
        mIAphorismsAView.showLoading();
        mIAphorismsAModel.getListData(page, rows, new CallBack() {

            @Override
            public void onSuccess(Object response) {
                mIAphorismsAView.dismissLoading();
                mIAphorismsAView.response(response, mIAphorismsAView.RESPONSE_SUCCESS);
                mIAphorismsAView.showToast("数据加载成功!");
            }

            @Override
            public void onError(String error) {
                mIAphorismsAView.dismissLoading();
                mIAphorismsAView.response(error, mIAphorismsAView.RESPONSE_ERROR);
                mIAphorismsAView.showToast("数据加载失败!");
            }
        });
    }
}
/**
 * 泛型类的回调接口
 *
 * @param <T>
 */
public interface CallBack<T> {

    void onSuccess(T response);

    void onError(String error);
}

 

案例②

       对MVP模式的优化处理。因为在Presenter层持有了View层的强引用,若在请求结束之前,Activity(即View层)被销毁了,但是此时网络请求的数据还没有返回来,从而导致了Presenter一直持有Activity对象,使得Activity对象无法被收回,所以此时就发生了内存的这么一个泄露事件。所以,这里通过弱引用的一个方式来解决。

创建了一个Base包

/**
 * Presenter基类(优化MVP模式, 这里采用弱引用的方式, 防止内存泄露).
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public abstract class BasePresenter<T> {

    /**
     * 声明一个View接口类型的弱引用
     */
    protected Reference<T> mViewRef;

    /**
     * 与View建立关联
     *
     * @param view
     */
    public void attachView(T view) {
        mViewRef = new WeakReference<>(view);
    }

    /**
     * 获取View对象
     *
     * @return
     */
    protected T getView() {
        return mViewRef.get();
    }

    /**
     * 判断是否与View建立起关联
     *
     * @return
     */
    public boolean isViewAttached() {
        return mViewRef != null && mViewRef.get() != null;
    }

    /**
     * 解除与View的关联, 避免内存泄露事件的发生
     */
    public void detachView() {
        if (mViewRef != null) {
            mViewRef.clear();
            mViewRef = null;
        }
    }
}
/**
 * MvpActivity基类.
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public abstract class BaseMvpActivity<V, T extends BasePresenter<V>> extends AppCompatActivity {

    /**
     * Presenter对象
     */
    protected T mPresenter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 创建Presenter对象
        mPresenter = createPresenter();
        // 将View与Presenter对象建立起关联
        mPresenter.attachView((V) this);
    }

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

    /**
     * 销毁View的关联
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mPresenter.detachView();
    }
}

M层

/**
 * 数据接口层.
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public interface IAphorismsAModel {

    /**
     * 请求网络获取数据列表
     *
     * @param page     页码
     * @param rows     一次请求返回多少数据
     * @param callBack 回调函数
     */
    public void getListData(int page, int rows, CallBack callBack);
}
/**
 * 数据实现层.
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public class AphorismsAModelImpl implements IAphorismsAModel {

    /**
     * 请求网络获取数据列表
     *
     * @param page     页码
     * @param rows     一次请求返回多少数据
     * @param callBack 回调函数
     */
    @Override
    public void getListData(int page, int rows, final CallBack callBack) {
        String param = "key=9d3ce9c83fcd4c418dce2937c29b6414&keyword=天才&page=" + page + "&rows=" + rows;
        String url = "http://api.avatardata.cn/MingRenMingYan/LookUp?" + param;
        OkHttpUtils.get()
                .url(url)
                .build()
                .execute(new StringCallback() {

                    @Override
                    public void onResponse(String response, int id) {
                        GsonUtils utils = GsonUtils.getInstance();
                        AphorismsEntity aphorismsEntity = utils.fromJson(response, AphorismsEntity.class);
                        if (aphorismsEntity != null) {
                            callBack.onSuccess(aphorismsEntity.getResult());
                        } else {
                            callBack.onError(response);
                        }
                    }

                    @Override
                    public void onError(Call call, Exception e, int id) {
                        callBack.onError(e.getMessage());
                    }
                });
    }
}

V层

/**
 * 视图接口.
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public interface IAphorismsAView {

    // 请求标记
    public int REQUEST_ONE = 0;
    public int REQUEST_TWO = 1;
    public int REQUEST_THREE = 2;

    // 响应标记
    public int RESPONSE_SUCCESS = 200;
    public int RESPONSE_ERROR = 404;
    public int RESPONSE_FAILURE = 500;

    public <T> T request(int requestFlag);

    /**
     * 请求返回的数据
     *
     * @param response
     * @param responseFlag
     * @param <T>
     */
    public <T> void response(T response, int responseFlag);

    /**
     * 显示网络加载框
     */
    public void showLoading();

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

    /**
     * 弹出提示
     *
     * @param msg
     */
    public void showToast(String msg);
}
/**
 * 显示名言警句.
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public class AphorismsActivity extends BaseMvpActivity<IAphorismsAView, AphorismsAPresenterImpl> implements IAphorismsAView {

    private SmartRefreshLayout mSmartRefreshLayout;
    private RecyclerView rcyAphorisms;
    private LoadingDialog loadingDialog;
    private AphorismsAdapter aphorismsAdapter;
    private List<AphorismsEntity.ResultBean> resultBeanList = new ArrayList<>();
    private int page = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_aphorisms);

        mSmartRefreshLayout = findViewById(R.id.refresh_layout);
        rcyAphorisms = findViewById(R.id.rcy_aphorisms);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        rcyAphorisms.setLayoutManager(layoutManager);
        rcyAphorisms.setHasFixedSize(true);
        rcyAphorisms.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
        rcyAphorisms.setItemAnimator(new DefaultItemAnimator());

        aphorismsAdapter = new AphorismsAdapter(this);
        rcyAphorisms.setAdapter(aphorismsAdapter);
        // item的点击事件
        aphorismsAdapter.setOnItemClickListener(new AphorismsAdapter.OnItemClickListener() {

            @Override
            public void onItemClick(View view, int position) {
                showToast(aphorismsAdapter.getData().get(position).getFamous_name());
            }
        });

        // 获取电影列表数据
        mPresenter.getListData(1, 10);

        // 刷新数据
        mSmartRefreshLayout.setOnMultiPurposeListener(new SimpleMultiPurposeListener() {

            @Override
            public void onRefresh(@NonNull RefreshLayout refreshLayout) {
                super.onRefresh(refreshLayout);
                runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        page = 1;
                        mPresenter.getListData(1, 10);
                        mSmartRefreshLayout.finishRefresh();
                    }
                });
            }

            @Override
            public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
                super.onLoadMore(refreshLayout);
                runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        mPresenter.getListData(++page, 10);
                    }
                });
            }
        });
    }

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

    @Override
    public <T> T request(int requestFlag) {
        return null;
    }

    @Override
    public <T> void response(T response, int responseFlag) {
        if (responseFlag == IAphorismsAView.RESPONSE_SUCCESS) {
            List<AphorismsEntity.ResultBean> list = (List<AphorismsEntity.ResultBean>) response;
            if (list != null && list.size() > 0) {
                resultBeanList.addAll(list);
                aphorismsAdapter.addData(resultBeanList);
                mSmartRefreshLayout.finishLoadMore();
            } else {
                showToast("数据已加载完毕");
                // 将不会再次触发加载更多事件
                mSmartRefreshLayout.finishLoadMoreWithNoMoreData();
                mSmartRefreshLayout.resetNoMoreData();
            }
        }
    }

    @Override
    public void showLoading() {
        loadingDialog = new LoadingDialog(this);
        loadingDialog.setLoadingText("加载中...");
        loadingDialog.show();
    }

    @Override
    public void dismissLoading() {
        if (loadingDialog != null) {
            loadingDialog.close();
        }
    }

    @Override
    public void showToast(String msg) {
        Toast.makeText(this, "mvp: " + msg, Toast.LENGTH_SHORT).show();
    }
}

P层

/**
 * 逻辑接口层.
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public interface IAphorismsAPresenter {

    /**
     * 请求网络获取数据列表
     *
     * @param page 页码
     * @param rows 一次请求返回多少数据
     */
    public void getListData(int page, int rows);
}
/**
 * 逻辑实现层.
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public class AphorismsAPresenterImpl extends BasePresenter<IAphorismsAView> implements IAphorismsAPresenter {

    private IAphorismsAModel mIAphorismsAModel;

    public AphorismsAPresenterImpl() {
        mIAphorismsAModel = new AphorismsAModelImpl();
    }

    /**
     * 请求网络获取数据列表
     *
     * @param page 页码
     * @param rows 一次请求返回多少数据
     */
    @Override
    public void getListData(int page, int rows) {
        getView().showLoading();
        mIAphorismsAModel.getListData(page, rows, new CallBack() {

            @Override
            public void onSuccess(Object response) {
                getView().dismissLoading();
                getView().response(response, IAphorismsAView.RESPONSE_SUCCESS);
                getView().showToast("数据加载成功!");
            }

            @Override
            public void onError(String error) {
                getView().dismissLoading();
                getView().response(error, IAphorismsAView.RESPONSE_ERROR);
                getView().showToast("数据加载失败!");
            }
        });
    }
}
/**
 * 泛型类的回调接口
 *
 * @param <T>
 */
public interface CallBack<T> {

    void onSuccess(T response);

    void onError(String error);
}

 

以下是两个案例中的源代码:

① 链接:https://pan.baidu.com/s/1tP38gO-xPYntaEszvme2IQ    提取码:u59t

② 链接:https://pan.baidu.com/s/1Nt9XNc0Ye651Mfnb6Kfwhg    提取码:n92w

两个案例的区别:

①中,使用的是常规的MVP模式做的;

②中,对MVP模式进行了优化处理,使用弱引用的方式对其进行了处理,防止内存泄漏。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值