Android-architecture之MVC、MVP、MVVM、Data-Binding

来源:互联网 发布:mac itunes铃声 编辑:程序博客网 时间:2024/04/30 03:21

  • 传送门
  • MVC
    • 结构简介
    • 实例分析
    • 总结
  • MVP
    • 结构简介
    • 为什么使用MVP模式
    • 实例分析
    • MVP与MVC的异同
  • MVVM
  • Data-Binding
    • 前言
    • 参考链接

传送门

Android Architecture(Is Activity God?)

MVC

结构简介

这里写图片描述
这里写图片描述

实例分析

这里写图片描述

Controller控制器式

public class MainActivity extends ActionBarActivity implements OnWeatherListener, View.OnClickListener {    private WeatherModel weatherModel;    private Dialog loadingDialog;    private EditText cityNOInput;    private TextView city;    private TextView cityNO;    private TextView temp;    private TextView wd;    private TextView ws;    private TextView sd;    private TextView wse;    private TextView time;    private TextView njd;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        weatherModel = new WeatherModelImpl();        initView();    }    /**     * 初始化View     */    private void initView() {        cityNOInput = findView(R.id.et_city_no);        city = findView(R.id.tv_city);        cityNO = findView(R.id.tv_city_no);        temp = findView(R.id.tv_temp);        wd = findView(R.id.tv_WD);        ws = findView(R.id.tv_WS);        sd = findView(R.id.tv_SD);        wse = findView(R.id.tv_WSE);        time = findView(R.id.tv_time);        njd = findView(R.id.tv_njd);        findView(R.id.btn_go).setOnClickListener(this);        loadingDialog = new ProgressDialog(this);        loadingDialog.setTitle(加载天气中...);    }    /**     * 显示结果     *     * @param weather     */    public void displayResult(Weather weather) {        WeatherInfo weatherInfo = weather.getWeatherinfo();        city.setText(weatherInfo.getCity());        cityNO.setText(weatherInfo.getCityid());        temp.setText(weatherInfo.getTemp());        wd.setText(weatherInfo.getWD());        ws.setText(weatherInfo.getWS());        sd.setText(weatherInfo.getSD());        wse.setText(weatherInfo.getWSE());        time.setText(weatherInfo.getTime());        njd.setText(weatherInfo.getNjd());    }    /**     * 隐藏进度对话框     */    public void hideLoadingDialog() {        loadingDialog.dismiss();    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.btn_go:                loadingDialog.show();                weatherModel.getWeather(cityNOInput.getText().toString().trim(), this);                break;        }    }    @Override    public void onSuccess(Weather weather) {        hideLoadingDialog();        displayResult(weather);    }    @Override    public void onError() {        hideLoadingDialog();        Toast.makeText(this, 获取天气信息失败, Toast.LENGTH_SHORT).show();    }    private  T findView(int id) {        return (T) findViewById(id);    }}

Model模型

public interface WeatherModel {    void getWeather(String cityNumber, OnWeatherListener listener);}
public class WeatherModelImpl implements WeatherModel {    @Override    public void getWeather(String cityNumber, final OnWeatherListener listener) {        /*数据层操作*/        VolleyRequest.newInstance().newGsonRequest(http://www.weather.com.cn/data/sk/ + cityNumber + .html,                Weather.class, new Response.Listener() {                    @Override                    public void onResponse(Weather weather) {                        if (weather != null) {                            listener.onSuccess(weather);                        } else {                            listener.onError();                        }                    }                }, new Response.ErrorListener() {                    @Override                    public void onErrorResponse(VolleyError error) {                        listener.onError();                    }                });    }

总结

  • 扩展性好、维护性、模块职责明确
  • 耦合性低(解耦)、V和M非真正意义上的分离

什么时候适合使用MVC设计模式?

当一个小的项目且无需频繁修改需求就不用MVC框架来设计了,那样反而觉得代码过度设计,代码臃肿。一般在大的项目中,且业务逻辑处理复杂,页面显示比较多,需要模块化设计的项目使用MVC就有足够的优势了。

MVP

结构简介

Drawing
这里写图片描述

为什么使用MVP模式

在Android开发中,Activity并不是一个标准的MVC模式中的Controller,它的首要职责是加载应用的布局和初始化用户界面,并接受并处理来自用户的操作请求,进而作出响应。随着界面及其逻辑的复杂度不断提升,Activity类的职责不断增加,以致变得庞大臃肿。当我们将其中复杂的逻辑处理移至另外的一个类(Presneter)中时,Activity其实就是MVP模式中View,它负责UI元素的初始化,建立UI元素与Presenter的关联(Listener之类),同时自己也会处理一些简单的逻辑(复杂的逻辑交由Presenter处理).

另外,回想一下你在开发Android应用时是如何对代码逻辑进行单元测试的?是否每次都要将应用部署到Android模拟器或真机上,然后通过模拟用户操作进行测试?然而由于Android平台的特性,每次部署都耗费了大量的时间,这直接导致开发效率的降低。而在MVP模式中,处理复杂逻辑的Presenter是通过interface与View(Activity)进行交互的,这说明了什么?说明我们可以通过自定义类实现这个interface来模拟Activity的行为对Presenter进行单元测试,省去了大量的部署及测试的时间。

实例分析

MVP模式

View与Model并不直接交互,而是使用Presenter作为View与Model之间的桥梁。其中Presenter中同时持有Viwe层以及Model层的Interface的引用,而View层持有Presenter层Interface的引用。当View层某个界面需要展示某些数据的时候,首先会调用Presenter层的某个接口,然后Presenter层会调用Model层请求数据,当Model层数据加载成功之后会调用Presenter层的回调方法通知Presenter层数据加载完毕,最后Presenter层再调用View层的接口将加载后的数据展示给用户。这就是MVP模式的整个核心过程。

官方模式图

android-architecture官方传送门
这里写图片描述

案例

这里以暴风体育中的话题列表为例来进行介绍:

这里写图片描述
这里写图片描述
TopicModel

public interface TopicModel {    /**     * 加载话题列表首页数据     *     * @param context     * @param listener     */    void loadTopicList(Context context, TopicModelImpl.OnLoadTopicListListener listener);    /**     * 从本地数据库中获取我关注的话题数据     *     * @param context     * @param listener     * @return     */    ArrayList<TopicItem> loadFollowTopic(Context context, TopicModelImpl.OnLoadTopicListListener listener);    /**     * 全部话题加载更多数据     *     * @param context     * @param paramMap     * @param listener     */    void loadMoreAllTopic(Context context, Map<String, String> paramMap, TopicModelImpl.OnLoadTopicListListener listener);    /**     * 更新我关注的话题的最新帖子数和帖子最近的更新时间     *     * @param context     * @param threadItem     * @param listener     */    void updateThreadItem(final Context context, ThreadItem threadItem, TopicModelImpl.OnLoadTopicListListener listener);}

TopicPresenter

public interface TopicPresenter {    /**     * 加载话题列表首页数据     *     * @param context     */    void loadTopicList(Context context);    /**     * 全部话题加载更多数据     *     * @param context     * @param paramMap     */    void loadMoreAllTopic(Context context, Map<String, String> paramMap);    /**     *     * @param context     * @return     */    ArrayList<TopicItem> loadFollowTopic(Context context);}

TopicView

public interface TopicView {    void showProgress();    void addTopics(List<TopicItem> topicList);    void addSwipeUpItem(SwipeUpItem item);    void addLoadMoreTopics(List<TopicItem> topicList);    void hideProgress();    void showLoadFailMsg();    //二次请求需要重新刷新界面    void notifyAdapter();}

TopicModelImpl

/** * DES: * Created by sushuai on 2016/4/13. */public class TopicModelImpl implements TopicModel {    private static final String TAG = "TopicModelImpl";    /**     * 加载话题列表首页数据     *     * @param context     * @param listener     */    @Override    public void loadTopicList(final Context context, final OnLoadTopicListListener listener) {        AsyncHttpRequest.doASynGetRequest(context, UrlContainer.HOME_TOPIC, null, true, new AsyncHttpRequest.CallBack() {            @Override            public void fail(String ret) {                listener.onFailure(Net.ErrorNo.NO_DATA);            }            @Override            public void call(String data) {                try {                    ArrayList<TopicItem> items = (ArrayList<TopicItem>) TopicListDataParseUtils.readJsonTopicLists(data, listener);                    //items.addAll(0, loadFollowTopic(context, listener));                    if (items != null) {                        listener.onSuccess(items);                    }                } catch (JSONException e) {                    e.printStackTrace();                    listener.onFailure(Net.ErrorNo.ERROR_JSON);                }            }        });    }    /**     * 从本地数据库中获取我关注的话题数据     *     * @param context     * @param listener     * @return     */    @Override    public ArrayList<TopicItem> loadFollowTopic(Context context, final OnLoadTopicListListener listener) {        ArrayList<TopicItem> items = new ArrayList<>();        ArrayList<ThreadItem> ThreadItems = (ArrayList<ThreadItem>) FollowTopicDao.getInstance(context).getLatest3Topics();        if (ThreadItems.size() <= 0) {            return items;        }        for (int i = 0; i < ThreadItems.size(); i++) {            ThreadItem threadItem = ThreadItems.get(i);            updateThreadItem(context, threadItem, listener);        }        TopicItem meItem = new TopicItem();        meItem.setType(TopicAdapter.TYPE_TOPIC_TITLE_ME);        items.add(meItem);        for (int i = 0; i < ThreadItems.size(); i++) {            TopicItem topicItem = new TopicItem();            topicItem.setType(TopicAdapter.TYPE_TOPIC_THREAD);            topicItem.setOther(ThreadItems.get(i));            items.add(topicItem);        }        return items;    }    /**     * 更新我关注的话题的最新帖子数和帖子最近的更新时间     *     * @param context     * @param threadItem     * @param listener     */    @Override    public void updateThreadItem(final Context context, final ThreadItem threadItem, final OnLoadTopicListListener listener) {        Map<String, String> map = new HashMap<>();        map.put(Net.Field.id, String.valueOf(threadItem.getId()));        final int prePosts = threadItem.getCount();        AsyncHttpRequest.doASynGetRequest(context, UrlContainer.GET_TOPIC_POSTS, (HashMap<String, String>) map, true, new AsyncHttpRequest.CallBack() {            @Override            public void fail(String ret) {            }            @Override            public void call(String data) {                try {                    JSONObject jo = new JSONObject(data);                    int errno = DataParseUtils.getJsonInt(jo, Net.Field.errno);                    if (errno == Net.ErrorNo.SUCCESS) {                        JSONObject jsonObj = DataParseUtils.getJsonObj(jo, Net.Field.data);                        int count = DataParseUtils.getJsonInt(jsonObj, Net.Field.count);                        long latest_update_tm = DataParseUtils.getJsonLong(jsonObj, Net.Field.latest_update_tm);                        threadItem.setUpdateCount(count - prePosts);                        threadItem.setCount(count);                        threadItem.setUpdateTime(latest_update_tm);                        FollowTopicDao.getInstance(context).updatePostsById(threadItem.getId(), count);                        listener.onUpdateThreadItem();                    }                } catch (JSONException e) {                    e.printStackTrace();                }            }        });    }    /**     * 全部话题加载更多数据     *     * @param context     * @param paramMap     * @param listener     */    @Override    public void loadMoreAllTopic(Context context, Map<String, String> paramMap, final OnLoadTopicListListener listener) {        AsyncHttpRequest.doASynGetRequest(context, UrlContainer.TOPIC_LIST, (HashMap<String, String>) paramMap, true, new AsyncHttpRequest.CallBack() {            @Override            public void fail(String ret) {                listener.onFailure(Net.ErrorNo.NO_DATA);            }            @Override            public void call(String data) {                try {                    ArrayList<TopicItem> items = (ArrayList<TopicItem>) TopicListDataParseUtils.readMoreAllTopic(data, listener);                    if (items != null) {                        listener.onLoadMoreAllTopics(items);                    }                } catch (JSONException e) {                    e.printStackTrace();                    listener.onFailure(Net.ErrorNo.ERROR_JSON);                }            }        });    }    public interface OnLoadTopicListListener {        //加载话题列表首页数据成功        void onSuccess(List<TopicItem> list);        //加载话题列表首页数据失败        void onFailure(int erroNo);        //全部话题加载更多相关配置        void onLoadMoreSwipeUp(SwipeUpItem item);        //回去加载更多数据        void onLoadMoreAllTopics(List<TopicItem> list);        //更新我关注的话题的相关数据        void onUpdateThreadItem();    }}

TopicPresenterImpl

/** * DES: * Created by sushuai on 2016/4/13. */public class TopicPresenterImpl implements TopicPresenter, TopicModelImpl.OnLoadTopicListListener {    private static final String TAG = "TopicPresenterImpl";    private TopicModel mTopicModel;    private TopicView mTopicView;    public TopicPresenterImpl(TopicView topicView) {        this.mTopicModel = new TopicModelImpl();        this.mTopicView = topicView;    }    @Override    public void loadTopicList(Context context) {        mTopicModel.loadTopicList(context, this);    }    @Override    public void loadMoreAllTopic(Context context, Map<String, String> paramMap) {        mTopicModel.loadMoreAllTopic(context, paramMap, this);    }    @Override    public ArrayList<TopicItem> loadFollowTopic(Context context) {        return mTopicModel.loadFollowTopic(context,this);    }    @Override    public void onSuccess(List<TopicItem> list) {        mTopicView.hideProgress();        mTopicView.addTopics(list);    }    @Override    public void onFailure(int erroNo) {        mTopicView.hideProgress();        mTopicView.showLoadFailMsg();    }    @Override    public void onLoadMoreSwipeUp(SwipeUpItem item) {        mTopicView.addSwipeUpItem(item);    }    @Override    public void onLoadMoreAllTopics(List<TopicItem> list) {        mTopicView.addLoadMoreTopics(list);    }    @Override    public void onUpdateThreadItem() {        mTopicView.notifyAdapter();    }}

TabTopicFragment

/** * 话题 * SuShuai * 2016/4/12 14:39 */public class TabTopicFragment extends BaseFragment implements TopicAdapter.AdapterCallback, TopicView, IHandlerMessage, XListView.IXListViewListener {    // TODO: Rename parameter arguments, choose names that match    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER    private static final String TAG = "TabTopicFragment";    private static final String ARG_PARAM1 = "param1";    private static final String ARG_PARAM2 = "param2";    // TODO: Rename and change types of parameters    private String mParam1;    private String mParam2;    private XListView listView;    private TopicAdapter topicAdapter;    private ArrayList<TopicItem> topicList = new ArrayList<>();    private ArrayList<TopicItem> homeList = new ArrayList<>();    private ArrayList<TopicItem> followTopicList = new ArrayList<>();    private TopicPresenter mTopicPresenter;    private CommonHandler<TabTopicFragment> handler;    private SwipeUpItem swipeUpItem;    private View rootView;    private String after = "";    public TabTopicFragment() {        // Required empty public constructor    }    /**     * Use this factory method to create a new instance of     * this fragment using the provided parameters.     *     * @param param1 Parameter 1.     * @param param2 Parameter 2.     * @return A new instance of fragment TabTopicFragment.     */    // TODO: Rename and change types and number of parameters    public static TabTopicFragment newInstance(String param1, String param2) {        TabTopicFragment fragment = new TabTopicFragment();        Bundle args = new Bundle();        args.putString(ARG_PARAM1, param1);        args.putString(ARG_PARAM2, param2);        fragment.setArguments(args);        return fragment;    }    @Override    public void onAttach(Context context) {        super.onAttach(context);        LogHelper.e(TAG, "SuS--> onAttach: ");    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        if (getArguments() != null) {            mParam1 = getArguments().getString(ARG_PARAM1);            mParam2 = getArguments().getString(ARG_PARAM2);        }        mTopicPresenter = new TopicPresenterImpl(this);        LogHelper.e(TAG, "SuS--> onCreate: ");    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        LogHelper.e(TAG, "whb--> onCreateView: ");        if (rootView == null) {            rootView = inflater.inflate(R.layout.fragment_tab_topic, container, false);            initViews(rootView);        }        return rootView;    }    @Override    public void onActivityCreated(@Nullable Bundle savedInstanceState) {        LogHelper.e(TAG, "SuS--> onActivityCreated: ");        super.onActivityCreated(savedInstanceState);        initData();    }    private void initData() {        handler = new CommonHandler<TabTopicFragment>(this);        topicAdapter = new TopicAdapter(getActivity(), this);        listView.setAdapter(topicAdapter);        if (NetUtils.isNetworkAvaliable(getActivity())) {            showLoadingView();            mTopicPresenter.loadTopicList(getActivity());            followTopicList = mTopicPresenter.loadFollowTopic(getActivity());        } else {            if (topicList.size() > 0) {                topicAdapter.update(topicList);                ToastUtils.toast(getActivity(), "没有网络");                listView.restListView();                return;            }            showNetErroView(R.string.tips_net_error);        }    }    private void initViews(View v) {        setImmerseLayout(v.findViewById(R.id.common_back));        setTitleBar(v, R.string.tab_topic);        setLeftGone(v);        listView = (XListView) v.findViewById(R.id.lv_topic);        listView.setPullRefreshEnable(true);        listView.setPullLoadEnable(true);        listView.setAutoLoadEnable(true);        listView.setXListViewListener(this);    }    @Override    public void onAdapterCallback(int eventId, Object obj) {        if (isAdded()) {            BaofengStatistics.onUmengEvent(getActivity(), BfCountConst.TopicConst.BBS_MOREFOLLOW_CLICK);            LogHelper.v("umeng", "bbs_morefollow_click  计数一次");        }        ActivityUtil.startActivity(getActivity(), MoreFollowTopicActivity.class, null, false);    }    @Override    public void showProgress() {    }    @Override    public void addTopics(List<TopicItem> topicList) {        handler.obtainMessage(HandlerMsg.MSG_LOAD_TOPIC_LIST_SUC,                topicList).sendToTarget();    }    @Override    public void addSwipeUpItem(SwipeUpItem item) {        if (item == null) {            return;        }        handler.obtainMessage(HandlerMsg.MSG_LOAD_SWIPE_UP_ITEM,                item).sendToTarget();    }    @Override    public void addLoadMoreTopics(List<TopicItem> topicList) {        handler.obtainMessage(HandlerMsg.MSG_LOAD_MORE_TOPICS,                topicList).sendToTarget();    }    @Override    public void hideProgress() {        // handler.obtainMessage(HandlerMsg.MSG_DISMISS_LOADING).sendToTarget();    }    @Override    public void showLoadFailMsg() {        if (topicList == null || topicList.size() == 0) {            handler.obtainMessage(HandlerMsg.MSG_SHOW_EMPTY_CONTENT).sendToTarget();        }else {            handler.obtainMessage(HandlerMsg.MSG_SHOW_FAIL).sendToTarget();        }    }    @Override    public void notifyAdapter() {        handler.obtainMessage(HandlerMsg.MSG_NOTIFY_ADAPTER_CONTENT).sendToTarget();    }    @Override    public void handlerCallback(Message msg) {        switch (msg.what) {            case HandlerMsg.MSG_LOAD_TOPIC_LIST_SUC:                dealTopicListSuc(msg);                break;            case HandlerMsg.MSG_LOAD_SWIPE_UP_ITEM:                SwipeUpItem item = (SwipeUpItem) msg.obj;                this.swipeUpItem = item;                break;            case HandlerMsg.MSG_LOAD_MORE_TOPICS:                dealLoadMoreTopics(msg);                break;            case HandlerMsg.MSG_DISMISS_LOADING:                dismissLoadingView();                break;            case HandlerMsg.MSG_SHOW_EMPTY_CONTENT:                showContentEmptyView();                break;            case HandlerMsg.MSG_NOTIFY_ADAPTER_CONTENT:                topicAdapter.notifyDataSetChanged();                break;            case HandlerMsg.MSG_SHOW_FAIL:                ToastUtils.toast(getActivity(),R.string.error_no);                break;            default:                break;        }    }    private void dealLoadMoreTopics(Message msg) {        List<TopicItem> moreList = (List<TopicItem>) msg.obj;        int count1 = listView.getLastVisiblePosition();        int count2 = topicAdapter.getCount()-1+2;        if (moreList.size() < swipeUpItem.getLimit() && count1 == count2) {            ToastUtils.toast(getActivity(), "已到达底部");        }        if (moreList.size() > 0) {            after = TabTopicUtil.getLastKey(moreList);        }        TabTopicUtil.filterDuplicatedTopic(moreList,homeList);        this.topicList.addAll(moreList);        topicAdapter.update(this.topicList);        listView.restListView();    }    private void dealTopicListSuc(Message msg) {        List<TopicItem> topicList = (List<TopicItem>) msg.obj;        if (topicList.size() <= 0) {            showContentEmptyView();            return;        }        after = TabTopicUtil.getLastKey(topicList);        TabTopicUtil.removeDuplicateWithOrder(topicList);        topicList.addAll(0,followTopicList);        this.topicList = (ArrayList<TopicItem>) topicList;        this.homeList = (ArrayList<TopicItem>) topicList;        topicAdapter.update(topicList);        dismissLoadingView();        listView.restListView();    }    @Override    public void onRefresh() {        //handler.postDelayed(new Runnable() {        // @Override        //public void run() {        if (NetUtils.isNetworkAvaliable(getActivity())) {            mTopicPresenter.loadTopicList(getActivity());        } else {            if (topicList.size() > 0) {                ToastUtils.toast(getActivity(), "没有网络");                listView.restListView();                return;            }            showNetErroView(R.string.tips_net_error);        }        // }        //}, 2000);    }    @Override    public void onLoadMore() {        handler.postDelayed(new Runnable() {            @Override            public void run() {                Map<String, String> m = new HashMap<>();                int size = topicList.size();                if (size <= 0)                    return;                m.put(Net.Param.ID, String.valueOf(swipeUpItem.getId()));                m.put(Net.Param.AFTER, after);                m.put(Net.Param.LIMIT, String.valueOf(swipeUpItem.getLimit()));                if (NetUtils.isNetworkAvaliable(getActivity())) {                    mTopicPresenter.loadMoreAllTopic(getActivity(), m);                } else {                    ToastUtils.toast(getActivity(), "没有网络");                    listView.restListView();                }            }        }, 500);    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.fragment_net_error_subTree:                reQuestData();                break;            default:                break;        }    }    /**     * 重新请求数据     */    private void reQuestData() {        dismissNetErroView();        dismissContentEmptyView();        if (NetUtils.isNetworkAvaliable(getActivity())) {            showLoadingView();            mTopicPresenter.loadTopicList(getActivity());        } else {            showNetErroView(R.string.tips_net_error);        }    }    public interface HandlerMsg {        //获取话题列表成功        int MSG_LOAD_TOPIC_LIST_SUC = 2002;        //获取加载更多配置选项        int MSG_LOAD_SWIPE_UP_ITEM = 2003;        //加载更多话题        int MSG_LOAD_MORE_TOPICS = 2004;        //隐藏loading        int MSG_DISMISS_LOADING = 2005;        //显示空        int MSG_SHOW_EMPTY_CONTENT = 2006;        //二次请求刷新界面        int MSG_NOTIFY_ADAPTER_CONTENT = 2007;        //显示失败        int MSG_SHOW_FAIL = 2008;    }    @Override    public void onDestroyView() {//        unbindDrawables(getView());        LogHelper.e(TAG, "whb--> onDestroyView: ");        super.onDestroyView();    }    @Override    public void onResume() {        super.onResume();        LogHelper.d(TAG, "SuS--> onResume: ");            BaofengStatistics.onUmengEvent(getActivity(), BfCountConst.TopicConst.BBS_CHANNELLIST_SHOW);            LogHelper.v("umeng", "bbs_channelList_show  计数一次");        topicList.removeAll(followTopicList);        followTopicList = mTopicPresenter.loadFollowTopic(getActivity());        topicList.addAll(0,followTopicList);        topicAdapter.notifyDataSetChanged();        //initData();    }}

MVP与MVC的异同

MVC模式与MVP模式都作为用来分离UI层与业务层的一种开发模式被应用了很多年。在我们选择一种开发模式时,首先需要了解一下这种模式的利弊:

无论MVC或是MVP模式都不可避免地存如下弊端,这就导致了这两种开发模式也许并不是很小型应用。

  • 额外的代码复杂度和学习成本

但比起他们的优点,这点弊端基本可以忽略了:

  • 降低耦合度
  • 模块职责划分明显
  • 利于测试驱动开发
  • 代码复用
  • 隐藏数据
  • 代码灵活性

对于MVP与MVC这两种模式,它们之间也有很大的差异。以下是这两种模式之间最关键的差异:
MVP模式:

  • View不直接与Model交互,而是通过与Presenter交互来与Model间接交互
  • Presenter与View的交互是通过接口来进行的,更有利于添加单元测试
  • 通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑

MVC模式:

  • View可以与Model直接交互
  • Controller是基于行为的,并且可以被多个View共享
  • 可以负责决定显示哪个View

MVVM

这里写图片描述
这里写图片描述

Data-Binding

前言

  • 第三方的数据绑定框架随时有停止更新的风险,官方的则相对更稳定一些
  • 大量的findViewById,增加代码的耦合性
  • 虽然可以通过注解框架抛弃大量的findViewById,但是注解注定要拖慢我们代码的速度,Data Binding则不会,官网文档说还会提高解析XML的速度

这里不赘述了,下面几篇文章都讲的很详细!

精通 Android Data Binding
Android官方数据绑定框架DataBinding(一)
Android官方数据绑定框架DataBinding(二)
官方Data Binding Library

参考链接:

1、https://www.zhihu.com/question/21406685
2、http://liuling123.com/2015/12/mvp-pattern-android.html
3、http://www.2cto.com/kf/201506/405766.html
4、http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0313/2599.html
5、http://blog.csdn.net/qibin0506/article/details/47393725
6、http://zjutkz.net/2016/04/13/%E9%80%89%E6%8B%A9%E6%81%90%E6%83%A7%E7%97%87%E7%9A%84%E7%A6%8F%E9%9F%B3%EF%BC%81%E6%95%99%E4%BD%A0%E8%AE%A4%E6%B8%85MVC%EF%BC%8CMVP%E5%92%8CMVVM/#plg_nld=1&plg_auth=1&plg_nld=1&plg_dev=1&plg_uin=1&plg_usr=1&plg_vkey=1&plg_nld=1&more?hmsr=toutiao.io&utm_source=toutiao.io&plg_uin=1&plg_auth=1&utm_medium=toutiao.io&plg_dev=1&plg_nld=1&plg_usr=1&plg_vkey=1
7、http://blog.csdn.net/wusuopubupt/article/details/8817826
8、[https://github.com/LyndonChin/MasteringAndroidDataBinding](https://github.com/LyndonChin/MasteringAndroidDataBinding)
9、https://github.com/googlesamples/android-architecture
10、http://www.jianshu.com/p/569ab68da482
11、http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0425/4178.html
12、http://blog.csdn.net/vector_yi/article/details/24719873

2 0
原创粉丝点击