Android MVP with Fragment and RecyclerView

最近刚刚接触MVP模式,试着做一下笔记。

关于MVP模式

网上关于MVP模式的资料已经很多了,看了几篇介绍的,个人觉得Android MVP模式 简单易懂的介绍方式这篇讲得最通俗易懂了,而且也考虑到了很多方面。这里就不再赘述了。

MVP demo

网上大多数的博客给的demo都挺简单的,所以我想写一个稍微复杂点的demo,主要用到了Fragment和RecyclerView。主要是参考了github上的RecyclerView-Examples,不过他写得比较深一点,还用到了抽屉栏和一些其它的技术,所以我把RecyclerView这部分抽了出来,比较方便初学者的学习。
先上效果图:
mvp

然后是代码目录结构:
src

从这张图就可以很明显的感觉到了MVP的缺点了——代码量一下子变得好多。写这个demo的时候确实也花费了很多时间,不过写完后细想一下,觉得这是值得的,因为结构一下子变得很清晰,想定位某些问题的话很快便能找到对应的代码。也不至于说几天过后再回过头来看觉得这不是你的代码了。

大致思路

在PictureFragment的onResume方法中去模拟加载图片操作,由于这里是View和Model的交互,所以理所应当的交给PicturePresenter去处理。在PicturePresenterImpl中是通过PictureInteractor去和Model进行交互的。取得数据后,返回给LoaderListener的onFinish方法去处理,在该方法中又调用了PictureView的showPictures方法,最终完成了图片的加载和显示。
看起来会有点绕,不过当你习惯了之后便会觉得思路还是很清晰的,即当View想和Model交互时,交给Presenter去处理,Presenter通过Interactor取得Model中的数据后,又交给了View去进行显示。

PictureView

目前我写MVP的是写好布局文件后,先大概想一下该页面需要做什么UI操作,如进度条显示,Toast通知等,然后把这些已经确定的操作写进PictureView接口中,开发过程中如果还发现需要补充再添加进去就OK了。

public interface PictureView {
    void showProgressBar();
    void hideProgressBar();
    void showMsg(String msg);
    void showPictures(List<Picture> pictures);
}

没错,PictureView就是这么简单而已。

PictureFragment

首先需要说明的是,在写到这一步的时候,代码中和Presenter有关的代码都是还没添加进去的,请自动过滤掉先~
在PictureFragment中实现PictureView接口,在这一步中你完全可以假设你想要的数据已经取到了,可以尽情的做你想做的事了(尽管我们还没写Presenter)。看到没有,这里MVP的优势已经显现出来了。每一层都有自己的职责,你只需要管好自己的就行了。

public class PictureFragment extends Fragment implements PictureView{

    private RecyclerView mRecyclerView;
    private ProgressBar mProgress;

    private PictureAdapter mAdapter;
    private PicturePresenter mPresenter;

    public static PictureFragment newInstance() {
        return new PictureFragment();
    }

    public PictureFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_picture, container, false);
        initView(view);

        mPresenter = new PicturePresenterImpl(this);
        return view;
    }

    @Override
    public void onResume() {
        super.onResume();
        mPresenter.onResume();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mPresenter.onDestroy();
    }

    private void initView(View view) {
        mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
        mProgress = (ProgressBar) view.findViewById(R.id.progress_bar);
        setupRecyclerView();
    }

    private void setupRecyclerView() {
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    }

    @Override
    public void showProgressBar() {
        mProgress.setVisibility(View.VISIBLE);
        mRecyclerView.setVisibility(View.INVISIBLE);
    }

    @Override
    public void hideProgressBar() {
        mProgress.setVisibility(View.INVISIBLE);
        mRecyclerView.setVisibility(View.VISIBLE);
    }

    @Override
    public void showMsg(String msg) {
        Toast.makeText(getActivity(), msg, Toast.LENGTH_LONG).show();
    }

    @Override
    public void showPictures(List<Picture> pictures) {
        mAdapter = new PictureAdapter(pictures);
        mAdapter.setRecyclerItemClickListener(new OnRecyclerItemClickListener() {
            @Override
            public void onItemClick(int pos) {
                mPresenter.onItemClick(pos);
            }
        });
        mRecyclerView.setAdapter(mAdapter);
    }
}

写完Fragment之后,大概也知道自己需要在哪些地方做业务逻辑的操作了,接下来就可以写Presenter了。

PicturePresenter

在Presenter这部分是MVP中最关键且最难写的一部分了,所以在写这一步的时候请尽量保持头脑思路清晰。

public interface PicturePresenter {
    void onResume();
    void onDestroy();
    void onItemClick(int pos);
}

PicturePresenterImpl

在构造方法中,用PictureView初始化自己的成员变量,然后在onDestroy中设为NULL,防止内存泄露。
在与Model的交互中需要用到PictureInteractor,当然你也可以直接去取数据,不过我不觉得这是一种好的思路。所以把要交给View去操作的事先给办了,然后再来写PictureInteractor,再回过头来把未完成的事情做好。

public class PicturePresenterImpl implements PicturePresenter, LoaderListener {

    private PictureView mPictureView;
    private PictureInteractor mInteractor;

    public PicturePresenterImpl(PictureView pictureView) {
        this.mPictureView = pictureView;
        mInteractor = new PictureInteractorImpl();
    }

    @Override
    public void onResume() {
        mPictureView.showProgressBar();
        mInteractor.loadPictures(this);
    }

    @Override
    public void onDestroy() {
        mPictureView = null;
    }

    @Override
    public void onItemClick(int pos) {
        mPictureView.showMsg(String.valueOf(pos));
    }

    @Override
    public void onFinish(List<Picture> pictures) {
        mPictureView.hideProgressBar();
        mPictureView.showPictures(pictures);
    }
}

PictureInteractor

public interface PictureInteractor {
    void loadPictures(LoaderListener listener);
}

PictureInteractorImpl

@Override
public void loadPictures(final LoaderListener listener) {
    // 用Handler延时模拟下载操作
    new Handler(Looper.getMainLooper())
            .postDelayed(new Runnable() {
                @Override
                public void run() {
                    listener.onFinish(createPictures());
                }
            }, 2000);
}

private List<Picture> createPictures() {
    ArrayList<Picture> pictures = new ArrayList<>();
    for (int i = 0; i < pictureNames.length; i++) {
        pictures.add(new Picture(pictureNames[i], pictureImages[i]));
    }
    return pictures;
}

其它

关于其它部分,就不继续写下去了,不是MVP的重点,具体的请看源码

总结

在还没下笔开始写代码的时候,觉得MVP模式很难理解,甚至会觉得代码跳来跳去的很乱。但认真写下来之后却发现收获很多。
还有一点是不知道从哪开始入手,因为MVP把View和Model分开了,这两层就变成独立的了,突然间就不知道该从哪写入手了。所以,以上是我自己的一点经验总结吧,先把Model定下来,这是最容易的,毕竟你总得知道你写的页面需要什么数据吧,然后写View,在这个过程中确定自己需要做哪些业务逻辑的操作,接着写Presenter,接着再写Interactor。中间遇到一些暂时写不了的就先放着,等你写完其它的之后很容易就能定位到相应的代码的。
也许等我对MVP更熟悉了之后会有更好的思路。

最后,如果你看懂了这个Demo,建议看看我参考的RecyclerView-Examples,在这里你能进一步地理解MVP模式。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值