安卓MVC开发模式总结

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

 

1. 概述

       MVC(Model - View - Controller):即 模型 - 视图 - 控制器的简写,一种软件中的设计规范,用一种既有逻辑业务数据以及界面分离显示的设计模式,按照职责划分,将业务逻辑模块放到一个类里面去,在扩展和定制化和UI交互上,不需要重新对业务模块进行重新编写。

 

2. 架构及图解

MVC图解(图片来源于百度百科)
安卓MVC开发模式总结

Model即数据层,负责处理业务逻辑,请求数据,监听网络与数据库接口。

View即界面(UI)层,包括Activity/Fragment,用来显示来源于Model的数据,呈现给用户查看。

Controller即控制器层,处理业务逻辑的,传递用户的交互和更新Model中的数据。

 

3. 优缺点

优点:

① 在一定程度上降低了代码之间的耦合性;

② 重用性高;

③ 分工明确,各司所职。

缺点:

① 视图和控制器之间太过于紧密的联系,阻碍了各自的重用。

② 随着界面和业务逻辑的复杂度不断增加,Activity类的职责也不断增加,导致变得庞大臃肿。

③ 改造以适应MVC需要和建立分离的部件的代价很高。

 

4. 案例说明

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

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

案例①

安卓MVC开发模式总结

/**
 * 泛型类的回调接口
 *
 * @param <T>
 */
public interface CallBack<T> {

    void onSuccess(T response);

    void onError(String error);
}
/**
 * 数据模型接口层.
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public interface IAphorismsAModel {

    /**
     * 请求网络获取数据列表
     *
     * @param page     页码
     * @param rows     一次请求返回多少数据
     * @param callBack 回调函数(用来通知View层)
     */
    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 ("Succes".equals(aphorismsEntity.getReason())) {
                            callBack.onSuccess(aphorismsEntity.getResult());
                        } else {
                            callBack.onError(response);
                        }
                    }

                    @Override
                    public void onError(Call call, Exception e, int id) {
                        callBack.onError(e.getMessage());
                    }
                });
    }
}
/**
 * Controller控制器层(负责逻辑业务的处理).
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public class MainActivity extends AppCompatActivity implements CallBack {

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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // XML相当于View层(负责界面数据的展示, 与用户进行交互)
        setContentView(R.layout.activity_main);

        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) {
                String name = aphorismsAdapter.getData().get(position).getFamous_name();
                Toast.makeText(MainActivity.this, "mvc: " + name, Toast.LENGTH_SHORT).show();
            }
        });

        // 获取电影列表数据
        iAphorismsAModel = new AphorismsAModelImpl();
        loadingDialog = new LoadingDialog(this);
        loadingDialog.setLoadingText("加载中...");
        loadingDialog.show();
        iAphorismsAModel.getListData(1, 10, this);

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

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

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

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

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

    @Override
    public void onSuccess(Object response) {
        if (loadingDialog != null) {
            loadingDialog.close();
        }
        List<AphorismsEntity.ResultBean> list = (List<AphorismsEntity.ResultBean>) response;
        if (list != null && list.size() > 0) {
            resultBeanList.addAll(list);
            aphorismsAdapter.addData(resultBeanList);
            mSmartRefreshLayout.finishLoadMore();
        } else {
            Toast.makeText(this, "mvc: 数据已加载完毕", Toast.LENGTH_SHORT).show();
            // 将不会再次触发加载更多事件
            mSmartRefreshLayout.finishLoadMoreWithNoMoreData();
            mSmartRefreshLayout.resetNoMoreData();
        }
    }

    @Override
    public void onError(String error) {
        if (loadingDialog != null) {
            loadingDialog.close();
        }
        Toast.makeText(this, "mvc: " + error, Toast.LENGTH_SHORT).show();
    }
}

 

案例②

安卓MVC开发模式总结

/**
 * 泛型类的回调接口
 *
 * @param <T>
 */
public interface CallBack<T> {

    void onSuccess(T response);

    void onError(String error);
}
/**
 * 数据模型层(负责处理数据的加载或者存储).
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public class AphorismsAModel {

    /**
     * 请求网络获取数据列表
     *
     * @param page     页码
     * @param rows     一次请求返回多少数据
     * @param callBack 回调函数
     */
    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 ("Succes".equals(aphorismsEntity.getReason())) {
                            callBack.onSuccess(aphorismsEntity.getResult());
                        } else {
                            callBack.onError(response);
                        }
                    }

                    @Override
                    public void onError(Call call, Exception e, int id) {
                        callBack.onError(e.getMessage());
                    }
                });
    }
}
/**
 * Controller控制器层(负责逻辑业务的处理).
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public class AphorismsController {

    private AphorismsAModel aphorismsAModel;

    public AphorismsController() {
        aphorismsAModel = new AphorismsAModel();
    }

    /**
     * 请求网络获取数据列表
     *
     * @param page     页码
     * @param rows     一次请求返回多少数据
     * @param callBack 回调函数
     */
    public void getListData(int page, int rows, final CallBack callBack) {
        aphorismsAModel.getListData(page, rows, callBack);
    }
}
/**
 * View层(负责界面数据的展示, 与用户进行交互).
 *
 * @author luyh
 * @version 1.0
 * @date 2019/04/08
 */
public class MainActivity extends AppCompatActivity implements CallBack {

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

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

        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) {
                String name = aphorismsAdapter.getData().get(position).getFamous_name();
                Toast.makeText(MainActivity.this, "mvc: " + name, Toast.LENGTH_SHORT).show();
            }
        });

        // 获取电影列表数据
        aphorismsController = new AphorismsController();
        loadingDialog = new LoadingDialog(this);
        loadingDialog.setLoadingText("加载中...");
        loadingDialog.show();
        aphorismsController.getListData(1, 10, this);

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

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

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

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

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

    @Override
    public void onSuccess(Object response) {
        if (loadingDialog != null) {
            loadingDialog.close();
        }
        List<AphorismsEntity.ResultBean> list = (List<AphorismsEntity.ResultBean>) response;
        if (list != null && list.size() > 0) {
            resultBeanList.addAll(list);
            aphorismsAdapter.addData(resultBeanList);
            mSmartRefreshLayout.finishLoadMore();
        } else {
            Toast.makeText(this, "mvc: 数据已加载完毕", Toast.LENGTH_SHORT).show();
            // 将不会再次触发加载更多事件
            mSmartRefreshLayout.finishLoadMoreWithNoMoreData();
            mSmartRefreshLayout.resetNoMoreData();
        }
    }

    @Override
    public void onError(String error) {
        if (loadingDialog != null) {
            loadingDialog.close();
        }
        Toast.makeText(this, "mvc: " + error, Toast.LENGTH_SHORT).show();
    }
}

 

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

① 链接:https://pan.baidu.com/s/1jmhjnbOdYxi0qaSl1HzxHg    提取码:cwfy

② 链接:https://pan.baidu.com/s/1eGme7KjbIgpG4C75sfHvKA    提取码:3m3e

两个案例的区别:

①中,使用的是Activity直接作为Controller控制器来使用;

②中,将Controller控制器直接抽离出来一个类,而Activity仅仅属于视图层。