如何访问RecyclerView适配器的ViewHolder的数据源?
我RecyclerView的适配器的构造是这样的:如何访问RecyclerView适配器的ViewHolder的数据源?
Context context;
List<ConnectionItem> connections;
public ConnectionsListAdapter(Context context, List connections) {
this.context = context;
this.connections = connections;
}
适配器的声明后,我宣布一个静态ViewHolder类的RecyclerView,也可以用来处理任何按钮的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。它只是一个引用子视图的对象,因此不必一遍又一遍地调用findViewById()
。但这仍然是一个看法。
但是,您有一个模型数据作为参数的构造函数,并且它具有难闻的气味。
唯一属性/变量您
ViewHolder
应该是View
秒。您
ViewHolder
构造应该永远被调用的唯一事情是findViewById()
你还没有真正谈过适配器很多,但你会发现,你重写两种方法:onCreateViewHolder
和onBindViewHolder
。
在onCreateViewHolder
之内,您构建了适用于您的视图类型的ViewHolder
。而已。您可能需要根据视图类型膨胀不同的布局,但您只需在此处理视图。不要将任何模型数据传递给构造函数中的ViewHolder
。
在onBindViewHolder
,这里是您将视图挂接到模型数据的位置。
我经常做的事情是为我的ViewHolder
定义一个bind()
方法,以便非常清楚Model数据正在被切换。 bind()
方法获取数据并调用setText
和类似的方法来使视图反映适配器位置的模型数据。
但是现在我们来看看RecyclerView
的Adapter
设计的丑陋部分。适配器没有OnItemClickListener
。
谷歌认为这是一个更好的设计;无论如何,事件应该由列表项目视图来处理。我明白了。但问题是事件必须满足其模型数据,并且它是具有模型数据的适配器,而不是列表项视图。
谷歌强调,你不能使用final
的值,如位置;您需要拨打getAdapterPosition()
以索引模型数据。
所以现在我已经去了一个适应所有这些约束的模式。
我使用带位置参数的方法为事件侦听器定义了一个
interface
。我在适配器
创建的侦听器的实例,我绑定到一个
ViewHolder
我通过这个监听器实例(所以ViewHolder
确实有给听者一个参考,但不适配器每次)论
ViewHolder
事件处理程序,我称之为getAdapterPosition()
以获取列表项的位置,然后调用侦听器方法与位置适配器获得听者回调,访问正确的模型数据,并执行所需的操作
所以这里有一个例子:我有一个在线购物车,已选定的项目,即产品的列表有一个大X的删除按钮。现在我必须处理该删除按钮。
定义接口:
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);
}
在您的适配器,:
public ConnectionsListAdapter(Context context, List connections) { this.context = context; this.connections = connections; }
你应该有
public ConnectionsListAdapter(Context context, List<ConnectionItem> connections) { this.context = context; this.connections = connections; }
另外,我不认为有保持你的ViewHolder类的静态的需要。所以你可以通过connections.get(getAdapterPosition());
访问适配器列表数据