MVP在RecyclerView中的使用

引言
有时候,感觉老外的文章,思考深度比国内深很多,最近看到一篇如何
在RecyclerView中使用MVP的文章,感觉挺好,特翻译过来进行记录。

原文
RecyclerView in MVP — Passive view’s approach

译文
每次当使用RecyclerView(或者其他需要适配器的视图)的时候,最重要的就是如何处理数据。
很多时候,大家倾向于在Adapter中持有一个Collection合集(比如说List),用它来保存需要显示的数据。在MVP(Model-View-Presenter)模式中,我们一般会将数据保存在Presenter中;而在Adapter中持有数据,是一种很糟糕的情况,这会导致列表在两个不同的地方被引用,但我们数据发生变化时,我们需要同时变更两处的数据。
首先,在adapter中存储数据并能够操纵它(通过移除,增加或者更新相关元素)打破了被动视图的原理和一般的MVP模式规则,因为所有的演示的逻辑都应该是presenter的任务。那么如何解决这个问题呢?
首先,我们先通过我们的adapter能够通知presenter它所需要的数据,将每一个条目作为一种MVP视图进行展示。

public class RepositoriesRecyclerAdapter extends RecyclerView.Adapter<ReposRecyclerAdapter.RepoViewHolder> {

    private final RepositoriesListPresenter presenter;

    public ReposRecyclerAdapter(RepositoriesListPresenter repositoriesPresenter) {
        this.presenter = repositoriesPresenter;
    }

    @Override
    public RepositoryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new RepositoryViewHolder(LayoutInflater.from(parent.getContext())
                                                .inflate(R.layout.cell_repo_view, parent, false));
    }

    @Override
    public void onBindViewHolder(RepositoryViewHolder holder, int position) {
        presenter.onBindRepositoryRowViewAtPosition(position, holder);

    }

    @Override
    public int getItemCount() {
        return presenter.getRepositoriesRowsCount();
    }
}

你可能注意到了,我们将Holder传给了我们的presenter。

你个混蛋,persenter不能依赖于视图层!你现在将persenter和holder紧密耦合在一起了。

别担心,我们先来看看RepositoryViewHolder 的实现方式。

public class RepositoryViewHolder extends RecyclerView.ViewHolder implements RepositoryRowView {

    TextView titleTextView;
    TextView starsCountTextView;

    public RepositoryViewHolder(View itemView) {
        super(itemView);
        titleTextView = itemView.findViewById(R.id.repoTitleText);
        starsCountTextView = itemView.findViewById(R.id.repoStarsCountText);
    }

    @Override
    public void setTitle(String title) {
        titleTextView.setText(title);
    }

    @Override
    public void setStarCount(int starCount) {
        starsCountTextView.setText(String.format("%s ★", starCount));
    }
}

正如你所视,我们的RepositoryViewHolderRepositoryRowView的具体实现,这是一种典型的MVP中View层的接口。

interface RepositoryRowView {

    void setTitle(String title);

    void setStarCount(int starCount);
}

presenter中调用的是接口,而不是具体的实现。

public class RepositoriesListPresenter {

    private final List<Repository> repositories;

    ...

    public void onBindRepositoryRowViewAtPosition(int position, RepositoryRowView rowView) {
        Repository repo = repositories.get(position);
        rowView.setStarCount(repo.getStarsCount());
        rowView.setTitle(repo.getTitle());
    }

    public int getRepositoriesRowsCount() {
        return repositories.size();
    }

    ...

}

这样一来,每行需要的数据以及所有的逻辑都转移到了persent而,而且不会破坏简洁的架构(persenter对于视图层的具体实现一无所知,也不知道android框架的任何内容)。
总结
文章很简洁,将我们平时使用的adapter进行了更仔细的分层,将业务逻辑和展示进行了隔离,这是一种很好的实现理念,感觉很值得学习。

发布了16 篇原创文章 · 获赞 2 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/adfghjkl/article/details/76862072