【问题标题】:Implement onItemClickListener using MVP pattern使用 MVP 模式实现 onItemClickListener
【发布时间】:2019-06-29 06:25:46
【问题描述】:

我正在学习 MVP,但很困惑在哪里如何我应该在不破坏 mvp 概念的情况下实现 onClickListener。

遵循本指南:https://android.jlelse.eu/recyclerview-in-mvp-passive-views-approach-8dd74633158

我的实现。

适配器:

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


private final RepositoriesListPresenter presenter;

public RepositoriesRecyclerAdapter(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();
}

}

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));
    }
}

RepositoryRowView

interface RepositoryRowView {

    void setTitle(String title);

    void setStarCount(int starCount);
}

我看到的所有指南都是关于在 Adapter 中创建 onClickListener 对象,然后在 ViewHolder 中使用它,但是在这个实现中,我覆盖了我的演示者中的所有适配器函数并传递 onClickListener(与 Android 相关的东西)会与 mvp 模式相矛盾。在这种情况下该怎么办。也许有人可以写一个解决方案 - 真的很困惑。

我的主要目标是点击一个 recyclerview 项目并获取项目名称(通过 toast)

【问题讨论】:

    标签: android onclicklistener mvp


    【解决方案1】:

    OnClickListener 是 Android SDK 的一个接口。您的演示者应该对 Andriod SDK 一无所知。它应该是纯 Java,因此只需在 JVM 上使用单元测试即可对其进行测试。它不应该知道关于视图、RecyclerView、Adapter 或 ViewHolder 的任何信息。

    您的 onBindViewHolder 不违反此原则,因为它由一个抽象接口 - RepositoryRowView 分隔。

    您应该在适配器/viewholder 中实现 OnClickListener 并从那里调用您的演示者。

    public class RepositoryViewHolder extends RecyclerView.ViewHolder implements RepositoryRowView, View.OnClickListener {
    
        TextView titleTextView;
        TextView starsCountTextView;
        RepositoriesListPresenter presenter;
    
        public RepositoryViewHolder(View itemView, RepositoriesListPresenter presetner) {
            super(itemView);
            titleTextView = itemView.findViewById(R.id.repoTitleText);
            starsCountTextView = itemView.findViewById(R.id.repoStarsCountText);
            this.presenter = presenter;
            itemView.setOnClickListener(this);
        }
    
        @Override
        public void setTitle(String title) {
            titleTextView.setText(title);
        }
    
        @Override
        public void setStarCount(int starCount) {
            starsCountTextView.setText(String.format("%s ★", starCount));
        }
    
        @Override
        public void onClick(View view) {
            if (presenter != null) {
                presenter.onItemInteraction(getAdapterPosition());
            }
        }
    }
    

    【讨论】:

    • 如果我想改变所选项目的颜色怎么办?我无法将项目传回演示者(如您之前提到的),但我可以传递位置(如您所示),现在 VIEW(片段)如何改变颜色或位置?
    • @JoshuaMad 您可以使用已有的抽象。您可以将位置和 RepositoryRowView(由您的 ViewHolder 实现,因此您只需添加“this”作为参数)给演示者。比您可以向 RepositoryRowView 类添加方法。诸如“markRowAs...”之类的东西及其实现会改变颜色。
    【解决方案2】:

    与其在你的adapter中调用presenter,我宁愿做一个click的接口来从view调用它,因为你会在你的view中实例化这个adapter,保持MVP模式与click是一件好事视图中的元素,而不是适配器本身。

    这个例子是用 Kotlin 写的,但我相信你会明白的。

    首先,只需制作一个简单的界面,在用户点击列表中的任何项目时调用您的点击事件。

    class EquipmentAdapter(private val context: Context,private var equipmentList:ArrayList<Equipment>,itemListener:RecyclerViewClickListener): RecyclerView.Adapter<EquipmentAdapter.EquipmentViewHolder>() {
    
        interface RecyclerViewClickListener {
            fun recyclerViewListClicked(v: View?, position: Int)
        }
    
        companion object{
            var itemClickListener: RecyclerViewClickListener? = null
            var equipmentSearchList:ArrayList<Equipment>? = null
        }
    
        init {
            equipmentSearchList = equipmentList
            itemClickListener = itemListener
        }
    

    然后,在你的 ViewHolder 中你应该调用这个接口来处理点击

    inner class EquipmentViewHolder(itemView: View): RecyclerView.ViewHolder(itemView), View.OnClickListener {
        val equipmentName:TextView = itemView.txt_equipmentname
    
        init {
            itemView.setOnClickListener(this)
        }
    
        override fun onClick(v: View?) {
            itemClickListener?.recyclerViewListClicked(v, adapterPosition)
        }
    }
    

    最后,只需在调用适配器的视图中实现点击接口,然后在适配器内部管理演示者交互

    class EquipmentActivity : BaseActivity(), EquipmentContract.EquipmentView, EquipmentAdapter.RecyclerViewClickListener ...
    

    并实现点击方法

    override fun recyclerViewListClicked(v: View?, position: Int) {
        presenter.onItemInteraction(position)
    }
    

    这样做,您可以确保单击列表中的元素是从视图本身而不是从适配器进行的,在这里,您可以像往常一样与演示者交互,还可以做更多的事情来保持你的项目干净。

    【讨论】:

    • 这个答案应该被标记为正确。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多