gpt4 book ai didi

java - 如何访问 RecyclerView 适配器的 ViewHolder 的数据源?

转载 作者:塔克拉玛干 更新时间:2023-11-02 22:19:24 26 4
gpt4 key购买 nike

我的 RecyclerView 适配器的构造函数如下所示:

Context context;
List<ConnectionItem> connections;

public ConnectionsListAdapter(Context context, List connections) {
this.context = context;
this.connections = connections;
}

在适配器声明之后,我为 RecyclerView 声明了一个静态 ViewHolder 类,它还处理任何按钮的 onClicks:

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

public Context context;

public ImageView connectionImage;
public TextView connectionName;
public ImageButton startMsg;

public ViewHolder(View itemView, List<ConnectionItem> connections) {
super(itemView);
...
startMsg.setOnClickListener(this);
}

@Override
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), ChatActivity.class);
intent.putExtra("name", connections.get(getAdapterPosition()).getName()); // Error because accessing from static context
intent.putExtra("id", connections.get(getAdapterPosition()).getUid()); // Error because accessing from static context
context.startActivity(intent);
}
}

问题是 connections 无法从 ViewHolder 静态类中的静态上下文访问。我的 ViewHolder 从 RecyclerView 适配器获取信息的最佳方式是什么?作为一种解决方法,我将数据源传递给 ViewHolder 的构造函数,并在 ViewHolder 中为数据源创建一个新的实例变量:

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public Context context;
public List<ConnectionItem> connections;

public ImageView connectionImage;
public TextView connectionName;
public ImageButton startMsg;

public ViewHolder(View itemView, List<ConnectionItem> connections) {
super(itemView);
this.connections = connections;
...
startMsg.setOnClickListener(this);
}

@Override
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), ChatActivity.class);
intent.putExtra("name", connections.get(getAdapterPosition()).getName()); // Okay now
intent.putExtra("id", connections.get(getAdapterPosition()).getUid()); // Okay now
context.startActivity(intent);
}

我的方法是否会破坏 ViewHolder 模式或在未来产生任何其他问题?

最佳答案

您的责任/顾虑有点困惑。

在 MVC 术语中,ViewHolder 实际上是一个 View 。它只是一个引用 subview 的对象,因此不必一遍又一遍地调用 findViewById()。但它仍然是一个真正的观点。

但是,您有一个以模型数据作为参数的构造函数,这有一股难闻的气味。

  • 您的 ViewHolder 应具有的唯一属性/变量是 View

  • ViewHolder 构造函数唯一应该调用的是 findViewById()

您并没有真正谈论过您的适配器,但您会注意到您覆盖了两个方法:onCreateViewHolderonBindViewHolder

onCreateViewHolder 中,您构建适用于您的 View 类型的 ViewHolder。而已。您可能需要根据 View 类型膨胀不同的布局,但您只是在这里处理 View 。不要将任何模型数据传递给构造函数中的 ViewHolder

onBindViewHolder 中,这里 是您将 View 连接到模型数据的地方。

我经常做的事情是为我的 ViewHolder 定义一个 bind() 方法,这样就可以非常清楚地传递哪些模型数据。 bind() 方法获取数据并调用 setText 和类似方法以使 View 反射(reflect)该适配器位置的模型数据。

但现在我们来到了 RecyclerViewAdapter 设计中丑陋的部分。适配器没有 OnItemClickListener

谷歌认为这是一个更好的设计;无论如何,事件应该由列表项 View 处理。我明白了。但问题是事件必须满足它的模型数据,并且它是具有模型数据的适配器,而不是列表项 View 。

并且 Google 强调您不能对位置等值使用 final;您需要调用 getAdapterPosition() 来索引模型数据。

所以现在我找到了一个可以适应所有这些约束的模式。

  • 我使用采用位置参数的方法为事件监听器定义了一个接口(interface)

  • 我在适配器中创建一个监听器实例

  • 每次绑定(bind)到 ViewHolder 时,我都会传递此监听器实例(因此 ViewHolder 确实有对监听器的引用,但没有 适配器)

  • ViewHolder 的事件处理程序上,我调用 getAdapterPosition() 来获取列表项的位置,然后我用它调用监听器方法位置

  • 适配器获取监听器回调,访问正确的模型数据并执行所需的操作

下面是一个示例:我有一个已选择的项目列表,即在线购物车中的产品有一个带有大 X 的删除按钮。现在我必须处理该删除按钮。

定义接口(interface):

    interface OnItemRemovedListener {

void itemRemoved(int position);
}

在适配器中创建监听器实例

    private OnItemRemovedListener mCallback;

在适配器构造函数中设置它:

    mCallback = new OnItemRemovedListener() {
@Override
public void itemRemoved(int position) {
mItemList.remove(position);
notifyDataSetChanged();
}
};

ViewHolder 子类:

public static class ProductItemViewHolder extends RecyclerView.ViewHolder {

private TextView mProductName;

private Button mRemoveButton;

private OnItemRemovedListener mListener;

public ProductItemViewHolder(View itemView) {
super(itemView);
mProductName = (TextView) itemView.findViewById(R.id.product_name);
mRemoveButton = (Button) itemView.findViewById(R.id.remove_button);
}

public void bind(Model data, OnItemRemovedListener listener) {

mProductName.setText(data.getProductName());
mListener = listener;
mRemoveButton.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View view) {
int position = getAdapterPosition();
if (position >= 0) {
mListener.itemRemoved(position);
}
}
});
}
}

然后 onBindViewHolder 覆盖看起来像这样:

    @Override
public void onBindViewHolder(ProductItemViewHolder holder, int position) {

holder.bind(mItemList.get(position), mCallback);
}

关于java - 如何访问 RecyclerView 适配器的 ViewHolder 的数据源?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38574912/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com