欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android MVP MVVM浅谈

程序员文章站 2022-07-02 10:02:55
...
  • 关于MVC、MVP、MVVM认识及介绍,请详细阅读并深入了解
    https://juejin.im/entry/56ebb4ad5bbb50004c440972

  • 关于MVC、MVP、MVVM的理解无外乎对数据的处理方式进一步的进行优化
    Android MVP MVVM浅谈

  • MVP P层实现Modle层获取数据,初始化Model,View层接口实现接口方法进行数据更新,数据加载,弹窗以及提示,而Activity仍然要实现View层接口在activity中对数据进行展示,相对于MVC而言是简化了很多,但是在Activity中仍然代码臃肿,需要处理很多数据展示等操作,下面是MVP P层以及Activity中代码。

  • `public class MoviePresenter implements MovieContract.IMoviePresenter {
    MovieContract.IMovieModel mIMovieModel;//M层
    MovieContract.IMovieView mIMovieView;//V层
    public int start = 0;//从第几个开始
    public int count = 4;//请求多少个

`

  List<Movies.SubjectsBean> mMovies = new ArrayList<>();//请求到的电影信息对象集合

    public MoviePresenter(MovieContract.IMovieView mIMovieView) {
        this.mIMovieView = mIMovieView;
        mIMovieModel = new MovieModel();
    }
@Override
    public void getMovie() {
        mIMovieView.showProgress();//通知V层显示对话框
        //每次刷新加载4个
        mIMovieModel.getMovie(start, count, new OnHttpCallBack<Movies>() {//有一个请求结果的回调,即我调用请求电影信息的方法了,M层要返回一个成功还是失败的信息给我
            @Override
            public void onSuccessful(Movies movies) {//获取电影信息成功了,返回movies对象
                mIMovieView.hideProgress();//通知V层隐藏对话框
                mMovies.addAll(movies.getSubjects());//追加数据
                mIMovieView.showData(mMovies);//将获取到的信息显示到界面之前
                mIMovieView.showBottom(start - 5);//实现换页效果
            }

            @Override
            public void onFaild(String errorMsg) {
                mIMovieView.hideProgress();//通知V层隐藏对话框
                mIMovieView.showInfo(errorMsg);//通知V层显示错误信息
            }
        });
        start = start + 4;//改变请求的起点
    }

    /**
     * 加载更多
     */
    @Override
    public void loadMoreMovie() {
        getMovie();
    }
**Activity端代码**

public class MovieActivity extends BaseActivity implements MovieContract.IMovieView {
    MoviePresenter mMoviePresenter;
    private ProgressDialog mProgressDialog;
    @InjectView(R.id.rv_movie_list)
    RecyclerView rvMovieList;
    @InjectView(R.id.store_house_ptr_frame)
    PtrFrameLayout storeHousePtrFrame;
    private TextView load_more;//加载更多的按钮

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initView();
        mMoviePresenter = new MoviePresenter(this);
        mMoviePresenter.getMovie();//启动软件时默认加载
    }

    @Override
    protected void $setToolBar() {
        super.$setToolBar();
        setTitle("豆瓣Top250的电影");
        setLeftImage(R.drawable.back);
        setRightTitle("电影");
    }

    /**
     * 初始化布局
     */
    private void initView() {
        setContentView(R.layout.content_movie);
        ButterKnife.inject(this);
        $setToolBar();
        initPtr();
        rvMovieList.setLayoutManager(new LinearLayoutManager(mActivity));//设置为listview的布局
        rvMovieList.setItemAnimator(new DefaultItemAnimator());//设置动画
        rvMovieList.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));//添加分割线
    }

    /**
     * 初始化(配置)下拉刷新组件
     */
    private void initPtr() {
        //下面是一些基础的配置,直接拿来用就可以 不用深究
        storeHousePtrFrame.setResistance(1.7f);
        storeHousePtrFrame.setRatioOfHeaderHeightToRefresh(1.2f);
        storeHousePtrFrame.setDurationToClose(200);
        storeHousePtrFrame.setDurationToCloseHeader(1000);
        storeHousePtrFrame.setPullToRefresh(false);
        storeHousePtrFrame.setKeepHeaderWhenRefresh(true);
        StoreHouseHeader header = new StoreHouseHeader(this);
        float scale = getResources().getDisplayMetrics().density;
        header.setPadding(0, (int) (15 * scale + 0.5f), 0, (int) (15 * scale + 0.5f));
        header.initWithString("GY");//自定义头显示的字样,设置图片的话看另外的api
//      header.invalidateDrawable();
        header.setTextColor(Color.RED);
        header.setBackgroundColor(Color.parseColor("#11000000"));
        storeHousePtrFrame.setHeaderView(header);//添加头
        storeHousePtrFrame.addPtrUIHandler(header);//同时也要加上这一句
        storeHousePtrFrame.setPtrHandler(new PtrHandler() {
            @Override
            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
                return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header);
            }

            @Override
            public void onRefreshBegin(PtrFrameLayout frame) {
                mMoviePresenter.loadMoreMovie();//下拉刷新的时候加载更多数据
                frame.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        storeHousePtrFrame.refreshComplete();
                    }
                }, 150);//为了增加用户体验 延迟0.15s再通知刷新结束
            }
        });

    }

    @Override
    public void showBottom(int lastIndex) {
        load_more.setText("点击加载更多");//设置最底下的加载更多显示的内容    加载中-->点击加载更多
        rvMovieList.scrollToPosition(lastIndex);
    }

    @Override
    public Context getCurContext() {
        return this;
    }

    @Override
    public void showProgress() {
        mProgressDialog = ProgressDialog.show(this, "提示", "正在获取中,请稍后...");
    }

    @Override
    public void hideProgress() {
        mProgressDialog.hide();
    }


    /**
     * 显示数据
     *
     * @param movies
     */
    @Override
    public void showData(List<Movies.SubjectsBean> movies) {
        //鸿洋大神的通用适配器(真的很好用哦)
        CommonAdapter<Movies.SubjectsBean> commonAdapter = new CommonAdapter<Movies.SubjectsBean>(this, R.layout.movie_item, movies) {

            @Override
            protected void convert(ViewHolder holder, Movies.SubjectsBean subjectsBean, int position) {
                String title = (position + 1) + "、" + subjectsBean.getTitle() + "/" + subjectsBean.getOriginal_title();
                holder.setText(R.id.tv_movie_title, title);//设置电影名
                String doc = "";
                for (Movies.SubjectsBean.DirectorsBean directorsBean : subjectsBean.getDirectors()) {
                    doc += directorsBean.getName() + "  ";
                }
                holder.setText(R.id.tv_movie_doc, "导演:" + doc);
                String casts = "";
                for (Movies.SubjectsBean.CastsBean castsBean : subjectsBean.getCasts()) {
                    casts += castsBean.getName() + "  ";
                }

                holder.setText(R.id.tv_movie_art, "主演:" + casts);
                String genres = "";
                for (String genre : subjectsBean.getGenres()) {
                    genres += genre + " ";
                }
                holder.setText(R.id.tv_movie_type, subjectsBean.getYear() + " / " + genres);//年份+分级
                holder.setText(R.id.tv_movie_grade, subjectsBean.getRating().getAverage() + "");//评分
                ImageView iv_pic = holder.getView(R.id.iv_movie_pic);
                Glide.with(mActivity)
                        .load(subjectsBean.getImages().getSmall())
                        .diskCacheStrategy(DiskCacheStrategy.ALL)//加快显示速度---缓存在本地磁盘
                        .into(iv_pic);//图片
            }
        };
        /**
         * 配置加载更多(通用适配器里面的类哦)
         */
        LoadMoreWrapper mLoadMoreWrapper = new LoadMoreWrapper(commonAdapter);//加载更多的包装器(传入通用适配器)
        View view = View.inflate(mActivity, R.layout.load_more, null);
        //要设置一下的布局参数,因为布局填充到包装器的时候,自己的一些属性会无效
        LinearLayout.LayoutParams mLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        view.setLayoutParams(mLayoutParams);
        load_more = (TextView) view.findViewById(R.id.tv_load_more);

        //监听点击加载更多事件
        load_more.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                load_more.setText("加载中...");//点击加载更多-->加载中
                mMoviePresenter.loadMoreMovie();
            }
        });
        mLoadMoreWrapper.setLoadMoreView(view);
        rvMovieList.setAdapter(mLoadMoreWrapper);//注意  这里添加的是包装器 不是适配器哦
    }

    @Override
    public void showInfo(String info) {
        ToastUtils.showToast(this, info);
    }
  • MVVM VM层实现数据请求监听器,初始化Modle实现类,调用获取数据的方法拿到数据,在成功失败的回调方法里面对数据进行提示,刷新,加载,对UI进行数据展示,前提是你引入DataBinding引入布局,不知道的可以先去查一下MVVM引入DataBinding如何进行实现的。下面是VM以及activity代码。
  • public class MovieListVm implements OnHttpCallBack<Movies>{
    public int start = 0;//从第几个开始
    public int count = 4;//请求多少个
    MovieModleBiz movieModleBiz;
 private TextView load_more;//加载更多的按钮
    List<Movies.SubjectsBean> mMovies = new ArrayList<>();//请求到的电影信息对象集合
    private ActivityMovieBinding binding;
    private Context context;
    MovieAdapter movieAdapter;
    private MovieListVm movieListVm;
    private ProgressDialog mProgressDialog;
    public MovieListVm(Context context,ActivityMovieBinding binding){
        this.binding=binding;
        this.context=context;
        init();
    }
    /**
     * 初始化
     */
    private void init() {
        movieModleBiz = new MovieModleBiz();
        firstLoadData();
    }

    /**
     * 首次加载
     */
    public void firstLoadData() {
         showProgress();//通知V层显示对话框
          movieModleBiz.getMovie(start, count,this);
          start = start + 4;//改变请求的起点
    }



    @Override
    public void onSuccessful(Movies movies) {


        hideProgress();//通知V层隐藏对话框
        mMovies.addAll(movies.getSubjects());//追加数据
        movieAdapter=new MovieAdapter(context,R.layout.movie_item,mMovies);
       showData(mMovies);//将获取到的信息显示到界面之前
       showBottom(start - 5);//实现换页效果
    }

    @Override
    public void onFaild(String errorMsg) {
        hideProgress();//通知V层隐藏对话框
        showInfo(errorMsg);//通知V层显示错误信息
    }

   public void showBottom(int lastIndex){
       binding.rvMovieList.scrollToPosition(lastIndex);
   };

    public void showProgress(){
        mProgressDialog = ProgressDialog.show(context, "提示", "正在获取中,请稍后...");
    };//显示进度条

    public void hideProgress(){

            mProgressDialog.hide();
    };//隐藏进度条

    public  void showData(List<Movies.SubjectsBean> movies){
        LoadMoreWrapper mLoadMoreWrapper = new LoadMoreWrapper(movieAdapter);//加载更多的包装器(传入通用适配器)
        View view = View.inflate(context, R.layout.load_more, null);
        //要设置一下的布局参数,因为布局填充到包装器的时候,自己的一些属性会无效
        LinearLayout.LayoutParams mLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        view.setLayoutParams(mLayoutParams);
        load_more = (TextView) view.findViewById(R.id.tv_load_more);

        //监听点击加载更多事件
        load_more.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                load_more.setText("加载中...");//点击加载更多-->加载中
                firstLoadData();
            }
        });
        mLoadMoreWrapper.setLoadMoreView(view);
       binding. rvMovieList.setAdapter(mLoadMoreWrapper);//注意  这里添加的是包装器 不是适配器哦
    };//显示数据到View上

    public void showInfo(String info){
        ToastUtils.showToast(context, info);
    };//提示用户,提升友好交互
}
**Acitivity代码**
public class MvvmMoviActivity extends BaseMvVmActivity<ActivityMovieBinding>{

    RecyclerView rvMovieList;
    PtrFrameLayout storeHousePtrFrame;
    private MovieListVm moviewListVm;
    @Override
    public int getLayoutId() {
        return R.layout.activity_movie;
    }

    @Override
    public void init(Bundle savedInstanceState) {
        initView();
        initVm();
    }

    private void initVm() {
      moviewListVm= new MovieListVm(this, viewDataBinding);
    }

    private void initView() {
        rvMovieList=viewDataBinding.rvMovieList;
        storeHousePtrFrame=viewDataBinding.storeHousePtrFrame;
        initPtr();
        rvMovieList.setLayoutManager(new LinearLayoutManager(this));//设置为listview的布局
        rvMovieList.setItemAnimator(new DefaultItemAnimator());//设置动画
        rvMovieList.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));//添加分割线
    }

    /**
     * 初始化(配置)下拉刷新组件
     */
    private void initPtr() {
        //下面是一些基础的配置,直接拿来用就可以 不用深究
        storeHousePtrFrame.setResistance(1.7f);
        storeHousePtrFrame.setRatioOfHeaderHeightToRefresh(1.2f);
        storeHousePtrFrame.setDurationToClose(200);
        storeHousePtrFrame.setDurationToCloseHeader(1000);
        storeHousePtrFrame.setPullToRefresh(false);
        storeHousePtrFrame.setKeepHeaderWhenRefresh(true);
        StoreHouseHeader header = new StoreHouseHeader(this);
        float scale = getResources().getDisplayMetrics().density;
        header.setPadding(0, (int) (15 * scale + 0.5f), 0, (int) (15 * scale + 0.5f));
        header.initWithString("GY");//自定义头显示的字样,设置图片的话看另外的api
//      header.invalidateDrawable();
        header.setTextColor(Color.RED);
        header.setBackgroundColor(Color.parseColor("#11000000"));
        storeHousePtrFrame.setHeaderView(header);//添加头
        storeHousePtrFrame.addPtrUIHandler(header);//同时也要加上这一句
        storeHousePtrFrame.setPtrHandler(new PtrHandler() {
            @Override
            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
                return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header);
            }

            @Override
            public void onRefreshBegin(PtrFrameLayout frame) {
               //下拉刷新的时候加载更多数据
                moviewListVm.firstLoadData();
                frame.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        storeHousePtrFrame.refreshComplete();
                    }
                }, 150);//为了增加用户体验 延迟0.15s再通知刷新结束
            }
        });

    }



}
  • 下面是在github上的源码,在了解了MVP和MVVM之后可以下载源码进行验证实现。
  • github链接