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

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

传送门

Android Architecture(Is Activity God?)

MVC

结构简介

Android-architecture之MVC、MVP、MVVM、Data-Binding_第1张图片
Android-architecture之MVC、MVP、MVVM、Data-Binding_第2张图片

实例分析

Android-architecture之MVC、MVP、MVVM、Data-Binding_第3张图片

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

结构简介

Android-architecture之MVC、MVP、MVVM、Data-Binding_第4张图片
Android-architecture之MVC、MVP、MVVM、Data-Binding_第5张图片

为什么使用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官方传送门
Android-architecture之MVC、MVP、MVVM、Data-Binding_第6张图片

案例

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


Android-architecture之MVC、MVP、MVVM、Data-Binding_第7张图片
TopicModel

public interface TopicModel {
    /**
     * 加载话题列表首页数据
     *
     * @param context
     * @param listener
     */
    void loadTopicList(Context context, TopicModelImpl.OnLoadTopicListListener listener);

    /**
     * 从本地数据库中获取我关注的话题数据
     *
     * @param context
     * @param listener
     * @return
     */
    ArrayList loadFollowTopic(Context context, TopicModelImpl.OnLoadTopicListListener listener);

    /**
     * 全部话题加载更多数据
     *
     * @param context
     * @param paramMap
     * @param listener
     */
    void loadMoreAllTopic(Context context, Map 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 paramMap);

    /**
     *
     * @param context
     * @return
     */
    ArrayList loadFollowTopic(Context context);

}

TopicView

public interface TopicView {
    void showProgress();

    void addTopics(List topicList);

    void addSwipeUpItem(SwipeUpItem item);

    void addLoadMoreTopics(List 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 items = (ArrayList) 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 loadFollowTopic(Context context, final OnLoadTopicListListener listener) {
        ArrayList items = new ArrayList<>();
        ArrayList ThreadItems = (ArrayList) 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 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) 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 paramMap, final OnLoadTopicListListener listener) {
        AsyncHttpRequest.doASynGetRequest(context, UrlContainer.TOPIC_LIST, (HashMap) 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 items = (ArrayList) 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 list);

        //加载话题列表首页数据失败
        void onFailure(int erroNo);

        //全部话题加载更多相关配置
        void onLoadMoreSwipeUp(SwipeUpItem item);

        //回去加载更多数据
        void onLoadMoreAllTopics(List 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 paramMap) {
        mTopicModel.loadMoreAllTopic(context, paramMap, this);
    }

    @Override
    public ArrayList loadFollowTopic(Context context) {
        return mTopicModel.loadFollowTopic(context,this);
    }

    @Override
    public void onSuccess(List 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 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 topicList = new ArrayList<>();
    private ArrayList homeList = new ArrayList<>();
    private ArrayList followTopicList = new ArrayList<>();
    private TopicPresenter mTopicPresenter;
    private CommonHandler 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(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 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 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 moreList = (List) 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 topicList = (List) msg.obj;
        if (topicList.size() <= 0) {
            showContentEmptyView();
            return;
        }
        after = TabTopicUtil.getLastKey(topicList);
        TabTopicUtil.removeDuplicateWithOrder(topicList);
        topicList.addAll(0,followTopicList);
        this.topicList = (ArrayList) topicList;
        this.homeList = (ArrayList) 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 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

Android-architecture之MVC、MVP、MVVM、Data-Binding_第8张图片
Android-architecture之MVC、MVP、MVVM、Data-Binding_第9张图片

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

你可能感兴趣的:(Android归纳)