安卓MVC开发模式总结
******再度回头看看安卓的MVC开发模式的总结******
1. 概述
MVC(Model - View - Controller):即 模型 - 视图 - 控制器的简写,一种软件中的设计规范,用一种既有逻辑业务、数据以及界面分离显示的设计模式,按照职责划分,将业务逻辑模块放到一个类里面去,在扩展和定制化和UI交互上,不需要重新对业务模块进行重新编写。
2. 架构及图解
Model:即数据层,负责处理业务逻辑,请求数据,监听网络与数据库接口。
View:即界面(UI)层,包括Activity/Fragment,用来显示来源于Model的数据,呈现给用户查看。
Controller:即控制器层,处理业务逻辑的,传递用户的交互和更新Model中的数据。
3. 优缺点
优点:
① 在一定程度上降低了代码之间的耦合性;
② 重用性高;
③ 分工明确,各司所职。
缺点:
① 视图和控制器之间太过于紧密的联系,阻碍了各自的重用。
② 随着界面和业务逻辑的复杂度不断增加,Activity类的职责也不断增加,导致变得庞大臃肿。
③ 改造以适应MVC需要和建立分离的部件的代价很高。
4. 案例说明
请求接口的数据来源于 https://www.avatardata.cn/Docs/Api/5bc6f2a4-927c-415f-80ae-8772b76c8c73
有请求次数的限制,所以需要使用的,可自行注册账号,进行测试使用。
案例①
/** * 泛型类的回调接口 * * @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(); } }
案例②
/** * 泛型类的回调接口 * * @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仅仅属于视图层。