美文网首页
Android开发MVP架构三分钟上手应用

Android开发MVP架构三分钟上手应用

作者: panam | 来源:发表于2017-02-20 00:01 被阅读0次

写在前面#

最近看到了好多朋友写的关于MVP架构详解,浅谈...对于看文章三分钟热度的我都没有看完...趁着周末有时间,写了个demo,针对MVP进行菜鸟级的解析(目的是简单了解和快速应用),下面聚精会神三分钟,看看你能不能有所收获.

一.MVC和MVP##

  • 这部分是必须要了解的,我这里也是使用了网上比较好的总结.

1.MVC##

MVC的全称为Model-View-Controller,即模型-视图-控制器,提出MVC目的为了分离界面和业务逻辑。

  • Model:处理数据和业务逻辑等
  • View:显示界面,展示结果等
  • Controller:控制流程,处理交互

android应用程序中mvc

  • View : layout目录下的xml布局文件,设计应用的ui界面。展现数据
  • Controller : Activity作为控制器,处理用户请求
  • Model : 一般是一个javaBean对象

举个栗子:MVC模式就像是书店里工作模式.

  • Model:可以理解为仓库管理员.他的工作是联系出版社,进货..
  • View:书架,所有的数都展示在书架上
  • Controller:老板,老板说这次我们需要买一批网络小说,这些书就出现在了书架上.这里面就涉及到M-V-C模式的.

2.MVP##

MVP的全称为Model-View-Presenter,即模型-视图-协调器(主持者)

  • Model:处理数据和业务逻辑等
  • View:显示界面,展示结果等
  • Presenter:协调Model和View模块工作,处理交互

关于优缺点等更深入的了解大家也可以看简书上相关文章,写得很仔细,我这里重点就是使用,所以就不做过多讲解.

二.案例分析##

针对MVP架构,查阅相关的文章和使用后我写了一个Demo,这个demo是为说明使用而量身设计的,有一定的代表性,源码在github上有.

1.效果图##

![Uploading GIF_776518.gif . . .]

![Uploading 2017-02-19_233539_830888.png . . .]

2.结构分析##

通过结构分析在脑海中有了一个基本框架,接下来就是去实现这个框架.

  • 共同点
  • 每个界面都是RecyclerView,有下拉刷新和上拉加载
  • 不同:
    • 每个RecyclerView的item内容不同,也就是对应的adapter不同

3.上代码##

3.1 代码结构###

参考我的工程结构

  • 1.抽取基类:抽取基类的好处就是找到共性内容少写代码,代码简洁清爽

  • 创建BaseFragment,作为fragment的基类

    • 共性:创建view视图,初始化操作

        public abstract class BaseFragment extends Fragment {
        public Context mContext;
      
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            mContext = getActivity();
            View view = initView();
            //绑定view
            ButterKnife.bind(this, view);
      
            //初始化
            init();
      
            return view;
        }
      
        public void init(){};
      
        /**
         * 实现的子类必须去实现的抽象方法,创建view
         * @return
         */
        public abstract View initView();
      

      }

  • 定义View接口

    • 定义抽象方法: 数据加载成功

    • View和Presenter是一对一或这一对多的,并且Presenter和View是通过接口交互的

        public interface BaseView {
            //数据加载成功后的回调
            void OnLoadDataSuccess();
        }
      
  • 创建HomePresenter,对应 是首页的presenter(指挥官,老板)

      public interface HomePresenter {
          //初始化请求网络数据
          void loadDataList();
      
          //下拉刷新
          void refresh();
      
          //加载更多
          void loadMoreData();
      
          ArrayList<HomeDataBean> getDataList();
      }
    
  • 创建BaseListFragment,这里大家需要特别注意,那些方法是要去子类必须去执行的,整体的业务逻辑应该是什么样的

          public abstract class BaseListFragment<T> extends BaseFragment implements BaseView {
      
          @BindView(R.id.base_recycle_view)
          RecyclerView       mBaseRecycleView;
          @BindView(R.id.base_down_refresh)
          SwipeRefreshLayout mBaseDownRefresh;
          private BaseListPresenter mPresenter;
          private RecyclerView.Adapter mAdapter;
      
          @Override
          public void init() {
              //初始化presenter
              mPresenter = getPresenter(this);
      
              initRecycleView();
      
              //加载数据
              mPresenter.loadDataList();
      
              //设置RecyclerView的滚动事件
              mBaseRecycleView.addOnScrollListener(scrollListener);
              //设置下拉刷新进度框的颜色,参数可以设置多个颜色,转一圈换一种颜色
              mBaseDownRefresh.setColorSchemeResources(R.color.colorPrimary);
              //监听下拉
              mBaseDownRefresh.setOnRefreshListener(listener);
      
          }
      
          private void initRecycleView() {
              mAdapter = getAdapter();
              mBaseRecycleView.setLayoutManager(new LinearLayoutManager(getContext()));//设置布局管理器
              mBaseRecycleView.setAdapter(mAdapter);
          }
      
      
          @Override
          public View initView() {
              return View.inflate(mContext, R.layout.base_item_fragment, null);
          }
      
          //加载数据成功
          @Override
          public void OnLoadDataSuccess() {
              mAdapter.notifyDataSetChanged();
              //更新完成数据之后,隐藏进度圈
              mBaseDownRefresh.setRefreshing(false);
          }
      
          private RecyclerView.OnScrollListener scrollListener = new RecyclerView.OnScrollListener() {
      
              @Override
              public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                  super.onScrollStateChanged(recyclerView, newState);
                  LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager();
                  //得到总共item条目数量,最后一个可见条目
                  int totaleItme = manager.getItemCount();
                  int lastVisibleItem = manager.findLastCompletelyVisibleItemPosition();
      
                  if (newState == RecyclerView.SCROLL_STATE_IDLE) {  //闲置状态
                      if (lastVisibleItem == totaleItme - 1) { //最后一条,第一条是0
                          //加载更多数据,开始位置是当前集合中的对象个数
                          mPresenter.loadMoreData();
                      }
                  }
              }
          };
      
          private SwipeRefreshLayout.OnRefreshListener listener = new SwipeRefreshLayout.OnRefreshListener() {
              @Override
              public void onRefresh() {
                  //下拉刷新事件的监听
                  mPresenter.refresh();
              }
          };
      
          /**
           * 子类必须返回presenter对象
           *
           * @return
           */
          protected abstract BaseListPresenter getPresenter(BaseListFragment<T> tBaseListFragment);
      
          /**
           * 定义抽象方法,子类必须返回adapter对象
           *
           * @return
           */
          public abstract RecyclerView.Adapter getAdapter();
      
      }
    

    上面给大家扔了一堆代码,看起来很枯燥,但是如果不放,我直接说会更枯燥.由于我画图水平一般,就没有拿出漂亮的结构图,见谅.上面代码就是在对app功能分析的基础上,去分析业务逻辑和基本框架,抽取共同点完成的.这里我们完成了一小步

  • 2.实现

    • 完成HomeFragment,实现BaseListFragment必须要实现两个抽象方法

        public class HomeFragment extends BaseListFragment {
      
        private HomePresenterImpl mHomePresenter;
      
        @Override
        protected BaseListPresenter getPresenter(BaseListFragment baseListFragment) {
            mHomePresenter = new HomePresenterImpl(baseListFragment);
            return mHomePresenter;
        }
      
        @Override
        public RecyclerView.Adapter getAdapter() {
                return new HomeRecycleViewAdapter(mContext, mHomePresenter.getDataList());
            }
        }
      
    • 创建HomePresenter的实现类,处理首页界面的业务逻辑

            public class HomePresenterImpl implements BaseListPresenter<HomeDataBean> {
            private static final String TAG = "HomePresenterImpl";
            private ArrayList<HomeDataBean> mDatas;
            private Handler                 mHandler;
            private HomeFragment            mBaseListFragment;
        
            public HomePresenterImpl(BaseListFragment baseListFragment) {
                mBaseListFragment = (HomeFragment) baseListFragment;
                mDatas = new ArrayList<>();
                mHandler = new Handler();
            }
        
            @Override
            public void loadDataList() {
                loadData(0);
            }
        
            @Override
            public void refresh() {
                mDatas.clear();
                loadData(0);
            }
        
            @Override
            public void loadMoreData() {
                loadData(mDatas.size());
            }
        
            @Override
            public ArrayList<HomeDataBean> getDataList() {
                return mDatas;
            }
        
            /**
             * 请求网络数据
             *
             * @param offSize 从什么位置开始下载,每次请求数据的长度是固定的10条
             */
            private void loadData(int offSize) {
                OkHttpClient httpClient = new OkHttpClient();
                String url = URLProviderUtil.getHomeUrl(offSize, 10);
        
                Request request = new Request.Builder().get().url(url).build();
                httpClient.newCall(request).enqueue(new Callback() {
                    @Override
                    public void onFailure(okhttp3.Call call, IOException e) {
        
                    }
        
                    @Override
                    public void onResponse(okhttp3.Call call, Response response) throws IOException {
                        //得到返回的json数据
                        String json = response.body().string();
                        Gson gson = new Gson();
                        //将json数据解析成包含对象的集合
                        ArrayList<HomeDataBean> list = gson.fromJson(json, new TypeToken<List<HomeDataBean>>() {
                        }.getType());
        
                        //将从网络上请求到的数据添加到集合中
                        mDatas.addAll(list);
                        //不能在子线程更新UI,通过handler添加
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                //数据加载完成-->通知更新数据..更新完成数据之后,隐藏进度圈
                                mBaseListFragment.OnLoadDataSuccess();
                            }
                        });
                    }
                });
            }
        }
      

    通过上面的操作完成了首页界面.

3.2 结构分析###

完成首页界面后可能对这个MVP还是没有什么直接的感受,要我来说,主要还是有下面几点明显的优势的

  • 降低耦合度,实现了Model和View真正的完全分离,可以修改View而不影响Modle

    • 针对上面的代码项目我们发现view层的工作就是当一切工作顺利执行后去显示数据,刷新数据,显示进度圈,出现错误显示错误(这里没有做),view层没有去操作数据.
    • Modle层的操作写在了Present中,就是加载数据,加载数据,加载完成告诉presenter,presenter会继续通知view执行操作.
  • 模块职责划分明显,层次清晰

    • 对应每个模块分工明确,你做完自己的工作就好了
  • 利于测试驱动开发

  • 还有等等..好处

缺点

  • Presenter中除了应用逻辑以外,还有大量的View->Model,Model->View的手动同步逻辑,造成Presenter比较笨重,维护起来会比较困难。
  • 代码复杂度大
  • 还有等等..

三.小结##

本以为理解简单写起了就容易了,没想到还是这么难,具体还是要大家去体会了,多用才能熟能生巧.我的源码在GitHub上有.大家可以看看.以后有好多内容还是会继续分享,第一也是为了提升自己,另一方面我们也可以共同进步.有问题还希望多多指导.我的仓库:https://github.com/hh-pan/Player.git

相关文章

网友评论

      本文标题:Android开发MVP架构三分钟上手应用

      本文链接:https://www.haomeiwen.com/subject/uwlswttx.html