2016-07-25 69 views
2

我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模式或創建任何其他未來的問題?

代替

回答

6

你的責任/關注點有點混亂。

在MVC中,ViewHolder確實是一個View。它只是一個引用子視圖的對象,因此不必一遍又一遍地調用findViewById()。但這仍然是一個看法。

但是,您有一個模型數據作爲參數的構造函數,並且它具有難聞的氣味。

  • 唯一屬性/變量您ViewHolder應該是View秒。

  • ViewHolder構造應該永遠被調用的唯一事情是findViewById()

你還沒有真正談過適配器很多,但你會發現,你重寫兩種方法:onCreateViewHolderonBindViewHolder

onCreateViewHolder之內,您構建了適用於您的視圖類型的ViewHolder。而已。您可能需要根據視圖類型膨脹不同的佈局,但您只需在此處理視圖。不要將任何模型數據傳遞給構造函數中的ViewHolder

onBindViewHolder,這裏是您將視圖掛接到模型數據的位置。

我經常做的事情是爲我的ViewHolder定義一個bind()方法,以便非常清楚Model數據正在被切換。 bind()方法獲取數據並調用setText和類似的方法來使視圖反映適配器位置的模型數據。

但是現在我們來看看RecyclerViewAdapter設計的醜陋部分。適配器沒有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); 
    } 
0

在您的適配器,:

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());訪問適配器列表數據

相關問題