![](/img/trans.png)
[英]How to let OnClick in viewholder recyclerview adapter Adapter call Activity's function
[英]How to access the data source of a RecyclerView adapter's ViewHolder?
我的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);
}
}
問題是無法從ViewHolder靜態類中的靜態上下文訪問connections
。 我的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()
。 但它仍然是一個觀點。
但是,你有一個帶有Model數據作為參數的構造函數,並且它有一個難聞的氣味。
ViewHolder
應該具有的唯一屬性/變量是View
。
您的ViewHolder
構造函數應該調用的唯一東西是findViewById()
你還沒有真正談論過你的適配器,但你會注意到你重寫了兩個方法: onCreateViewHolder
和onBindViewHolder
。
在onCreateViewHolder
您可以構建適用於您的視圖類型的ViewHolder
。 而已。 您可能需要根據視圖類型來擴展不同的布局,但您只是在這里處理視圖。 不要將任何Model數據傳遞給構造函數中的ViewHolder
。
在onBindViewHolder
,您可以在此處將View連接到Model數據。
我經常做的事情是為我的ViewHolder
定義一個bind()
方法,以便清楚地傳遞什么樣的模型數據。 bind()
方法獲取數據並調用setText
和類似方法,使視圖反映該適配器位置的Model數據。
但現在我們來到RecyclerView
的Adapter
設計的丑陋部分。 適配器沒有OnItemClickListener
。
谷歌認為這是一個更好的設計; 無論如何,事件應該由列表項視圖處理。 我明白了。 但問題是事件必須滿足其模型數據,並且它是具有模型數據的適配器,而不是列表項視圖。
谷歌強調,你不能使用像頭寸這樣的final
價值; 你需要調用getAdapterPosition()
來索引模型數據。
所以現在我已經采用了適應所有這些限制的模式。
我使用一個采用position參數的方法為事件監聽器定義一個interface
。
我在適配器中創建了一個偵聽器實例
每次我綁定到ViewHolder
我都會傳遞此偵聽器實例(因此ViewHolder
確實有對偵聽器的引用,但不是對適配器的引用)
在ViewHolder
的事件處理程序中,我調用getAdapterPosition()
來獲取列表項的位置,然后我用該位置調用listener方法
適配器獲取偵聽器回調,訪問正確的模型數據並執行所需的操作
所以這是一個例子:我有一個已經選擇的項目列表,即在線購物車中的產品有一個帶有大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());
訪問適配器列表數據connections.get(getAdapterPosition());
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.