Android MVP 实例运用

Android MVP介绍

随着技术的发展,Activity(View) 做的事情越来越多,动辄几百上千行的代码使得 Activity 越来越臃肿。为了更好的划分视图(View)和模型(Model)之间的职责,让 View 只处理数据的展示和用户的交互,把数据的处理交由 Model 处理。

在MVP模式里通常包含4个要素:

  1. View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity);
  2. View interface:需要View实现的接口,View通过View interface与Presenter进行交互,降低耦合,方便进行单元测试;
  3. Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合);
  4. Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑。

Android MVP 好处

MVP模式可以让显示界面和数据分离,我们开发的应用可以分离至少三层,这样也可以进行独立测试。更加的好维护(代码复用)数据分离有利于信息的隐蔽等等优点,相比较他的优点,缺点就可以忽略了。

Android MVP 实例

下图是采用MVP做的一个列表页面,实现了刷新,加载更多的功能。

目录结构

View 层

view 层的接口 用来与Presenter进行交互

public interface MovieView extends MVPView {
 
    void showLoading();
 
    void hideLoading();
 
    void showSwipeRefresh();
 
    void hideSwipeRefresh();
 
    boolean isSwipeRefresh();
 
    void showMovies(List<Movies> movieList);
 
    void appendMovies(List<Movies> movieList);
 
    void showToast(String content);
 
    boolean isTheListEmpty();
 
}
 

view 接口的实现类(Activity)

@Override
    protected void onCreate(BundlesavedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        // 设置 presenter
        moviePresenter = new MoviePresenter();
        moviePresenter.attachView(this);
        initializeSwipe();
        initializeRecycler();
    }
 
    /**
     * 初始化SwipeRefreshLayout和设置下拉刷新事件
     * */
    private void initializeSwipe() {
        mainSwipe.setColorSchemeResources(
                android.R.color.holo_blue_light,
                android.R.color.holo_red_light,
                android.R.color.holo_orange_light,
                android.R.color.holo_green_light);
        mainSwipe.setSize(SwipeRefreshLayout.LARGE);
        mainSwipe.setProgressViewEndTarget(true, 200);
        mainSwipe.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                moviePresenter.refresh();
            }
        });
    }
 
    /**
     * 初始化RecyclerView
     * */
    private void initializeRecycler() {
        mainRecyclerView.setLayoutManager(new GridLayoutManager(this, 2));
        adaper = new MovieAdaper();
        adaper.setRecyclerListListener(this);
        mainRecyclerView.setAdapter(adaper);
        mainRecyclerView.setOnScrollListener(recyclerScrollListener);
    }
 
    /*---------省略部分代码--------------*/
 
    /**
     * 加载更多的判断和触发
     * */
    private RecyclerView.OnScrollListenerrecyclerScrollListener = new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerViewrecyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
 
            int visibleItemCount    = mainRecyclerView.getLayoutManager().getChildCount();
            int totalItemCount      = mainRecyclerView.getLayoutManager().getItemCount();
            int pastVisibleItems    = ((GridLayoutManager) mainRecyclerView.getLayoutManager())
                    .findFirstVisibleItemPosition();
 
            if((visibleItemCount + pastVisibleItems) >= totalItemCount && !moviePresenter.isLoading()
                    && !moviePresenter.isLast()) {
                moviePresenter.loadMore();
            }
        }
    };
 

Presenter

处理网络请求以及数据分发

package com.jwenfeng.moviemvp.presenters;
 
importandroid.util.Log;
 
importcom.jwenfeng.moviemvp.model.Movies;
importcom.jwenfeng.moviemvp.view.MovieView;
 
importjava.util.List;
 
importcn.bmob.v3.BmobQuery;
importcn.bmob.v3.listener.FindListener;
 
/**
* 当前类注释:
* 项目名:MovieMVP
* 包名:com.jwenfeng.moviemvp.presenters
* 作者:jinwenfeng on 16/4/23 16:38
* 邮箱:823546371@qq.com
* QQ: 823546371
* 公司:南京穆尊信息科技有限公司
* © 2016 jinwenfeng
* ©版权所有,未经允许不得传播
*/
public class MoviePresenter extends Presenter {
 
    private MovieViewmovieView;
 
    private int limit = 8;        // 每页的数据是8条
    private int curPage = 0;        // 当前页的编号,从0开始
 
    private boolean isLoading = false;
    private boolean isLast = false;
 
    public void attachView(MovieViewmovieView) {
        this.movieView = movieView;
    }
 
    /**
     * 获取数据
     * */
    public void getData() {
        BmobQuery<Movies> query = new BmobQuery<>();
        query.setSkip(curPage * limit);
        query.setLimit(limit);
        query.findObjects(movieView.getContext(), new FindListener<Movies>() {
            @Override
            public void onSuccess(List<Movies> list) {
                if (list.size() > 0) {
                    if (movieView.isTheListEmpty()) {
                        movieView.hideLoading();
                    }
                    if (movieView.isSwipeRefresh()) {
                        movieView.showMovies(list);
                        movieView.hideSwipeRefresh();
                    } else {
                        Log.e("MoviePresenter",curPage+"----"+list.size());
                        movieView.appendMovies(list);
                    }
                    curPage++;
                    isLast = false;
                    isLoading = false;
                } else {
                    isLast = true;
                    isLoading = false;
                    movieView.showToast("没有更多数据了");
                }
            }
 
            @Override
            public void onError(int i, String s) {
                Log.e("MoviePresenter", i + "---" + s);
                movieView.showToast("查询失败:" + s);
            }
        });
    }
 
    /**
     * 加载更多
     * */
    public void loadMore() {
        if (!isLast && !isLoading){
            isLoading = true;
            getData();
        }
    }
 
    /**
     * 刷新
     * */
    public void refresh() {
        curPage = 0;
        movieView.showSwipeRefresh();
        isLoading = true;
        getData();
    }
 
    @Override
    public void start() {
        if (movieView.isTheListEmpty()) {
            movieView.showLoading();
            isLoading = true;
            getData();
        }
    }
 
    @Override
    public void stop() {
 
    }
 
    public boolean isLoading() {
        return isLoading;
    }
 
    public boolean isLast() {
        return isLast;
    }
}
 

Model

最后的Model就不贴了,就是一个bean

模式没有固定的,适合自己的就是最好的,欢迎关注,不足之处请指教,如果有兴趣可以参考放在GitHub上的源码

github地址: https://github.com/823546371/MovieMVP

本文地址: http://jwenfeng.com/?p=199

尊重原创,转载请注明:From 晓峰残月(http://jwenfeng.com) 侵权必究!

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章