2015-11-21 11 views
38

मैं एक RecyclerView.Adapter वर्ग के लिए निम्नलिखित कोड है और यह ठीक काम करता है:एक RecyclerView.Adapter के BindViewHolder के अंदर ऑनक्लिक लिस्टनर क्यों जोड़ रहा है खराब अभ्यास माना जाता है?

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.Viewholder> { 

    private List<Information> items; 
    private int itemLayout; 

    public MyAdapter(List<Information> items, int itemLayout){ 
     this.items = items; 
     this.itemLayout = itemLayout; 
    } 

    @Override 
    public Viewholder onCreateViewHolder(ViewGroup parent, int viewType) { 
     View v = LayoutInflater.from(parent.getContext()).inflate(itemLayout, parent, false); 
     return new Viewholder(v); 
    } 

    @Override 
    public void onBindViewHolder(Viewholder holder, final int position) { 
     Information item = items.get(position); 
     holder.textView1.setText(item.Title); 
     holder.textView2.setText(item.Date); 

     holder.itemView.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View view) { 
       Toast.makeText(view.getContext(), "Recycle Click" + position, Toast.LENGTH_SHORT).show(); 
      } 
     }); 

     holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { 
     @Override 
     public boolean onLongClick(View v) { 
      Toast.makeText(v.getContext(), "Recycle Click" + position, Toast.LENGTH_SHORT).show(); 
      return true; 
     } 
}); 
    } 

    @Override 
    public int getItemCount() { 
     return items.size(); 
    } 

    public class Viewholder extends RecyclerView.ViewHolder { 
     public TextView textView1; 
     public TextView textView2; 

     public Viewholder(View itemView) { 
      super(itemView); 
      textView1=(TextView) itemView.findViewById(R.id.text1); 
      textView2 = (TextView) itemView.findViewById(R.id.date_row); 

     } 
    } 
} 

हालांकि, मेरा मानना ​​है कि यह बुरा व्यवहार onBindViewHolder विधि में OnClickListener लागू करने के लिए है। यह बुरा अभ्यास क्यों है, और बेहतर विकल्प क्या है?

उत्तर

37

व्यूहोल्डर के अंदर अपने क्लिक तर्क को संभालने का कारण यह है क्योंकि यह अधिक स्पष्ट क्लिक श्रोताओं के लिए अनुमति देता है। जैसा कि कॉमन्सवेयर पुस्तक में व्यक्त किया गया है:

एक सूची दृश्य में एक रेटिंगबार की तरह क्लिक करने योग्य विजेट, पंक्तियों पर क्लिक घटनाओं के साथ लंबे समय से संघर्ष में थे। उन पंक्तियों को प्राप्त करना जिन्हें क्लिक किया जा सकता है, पंक्ति सामग्री के साथ भी क्लिक किया जा सकता है, कभी-कभी थोड़ा मुश्किल हो जाता है। RecyclerView के साथ, आप इस तरह की चीज को कैसे प्रबंधित करते हैं इस पर अधिक स्पष्ट नियंत्रण में हैं ... क्योंकि आप सभी ऑन-क्लिक हैंडलिंग तर्क स्थापित कर रहे हैं।

व्यूहोल्डर मॉडल का उपयोग करके आप ListView में पहले की तुलना में रीसाइक्लिंग व्यू में क्लिक हैंडलिंग के लिए बहुत से लाभ प्राप्त कर सकते हैं। मैं एक ब्लॉग पोस्ट में इस बारे में लिखा था मतभेद की तुलना - http://androidessence.com/recyclerview-vs-listview/

क्यों यह ViewHolder में के बजाय onBindViewHolder() में बेहतर है के लिए

के रूप में, वह यह है कि क्योंकि onBindViewHolder() प्रत्येक के लिए कहा जाता है और हर आइटम और क्लिक श्रोता सेट करने में कोई अनावश्यक है दोहराने का विकल्प जब आप इसे अपने व्यूहोल्डर कन्स्ट्रक्टर में एक बार कॉल कर सकते हैं। फिर, यदि आपका क्लिक प्रतिसाद आइटम की स्थिति पर निर्भर करता है, तो आप व्यूहोल्डर के भीतर से getAdapterPosition() पर कॉल कर सकते हैं। Here एक और उत्तर है जो मैंने दिया है यह दर्शाता है कि आप अपने व्यूहोल्डर वर्ग के भीतर से OnClickListener का उपयोग कैसे कर सकते हैं।

+1

अनावश्यक क्लिक श्रोता सेट अप से बचने के लिए यह करना चाहिए! लेकिन क्या हम इसे क्रिएटिव्यूहोल्डर() पर लागू कर सकते हैं क्योंकि ब्रूसलेट सुझाव देता है (नीचे जवाब देखें)। –

+1

@ सुजीतवाडव मुझे लगता है कि इसका एक ही प्रभाव होगा, क्योंकि 'ऑनक्रेट व्यूहोल्डर()' को केवल एक बार (प्रति व्यूहोल्डर) कहा जाता है, ताकि आप इसे अपने व्यूहोल्डर कन्स्ट्रक्टर के अंदर या 'ऑनक्रेट व्यूहोल्डर()' में व्यक्तिगत प्राथमिकता के रूप में लागू कर सकें । मैंने इसे वीएच में डालने की आदत विकसित की है, लेकिन आपको वह करना चाहिए जो आपको लगता है कि सबसे ज्यादा पठनीय है और भविष्य में आपको समझने में मदद करेगा। बस ब्रशलेट सुझाए गए प्रदर्शन कारणों के लिए 'onBindViewHolder() 'से बचें। – AdamMc331

+0

@ सुजीत @ एमसीएडैम मुझे 'व्यूहोल्डर' कन्स्ट्रक्टर की बजाय 'ऑनक्रेट व्यूहोल्डर()' में ऐसा करना पसंद है ताकि मैं अपना 'व्यूहोल्डर' वर्ग 'स्थिर' बना सकूं और एडाप्टर को संदर्भ में ' ViewHolder'।लेकिन आखिरकार यह ज्यादातर स्टाइल पसंद है, क्योंकि 'onCreateViewHolder()' और 'new ViewHolder()' के बीच एक-से-एक पत्राचार होना चाहिए। – Brucelet

9

onCreateViewHolder() विधि को की पहली बार कई बार viewType की आवश्यकता होगी। onBindViewHolder() विधि हर बार एक नया आइटम स्क्रॉल देखने के लिए बुलाया जाएगा, या इसका डेटा बदल गया है। आप onBindViewHolder() में किसी भी महंगी परिचालन से बचना चाहते हैं क्योंकि यह आपकी स्क्रॉलिंग को धीमा कर सकता है। यह onCreateViewHolder() में चिंता का विषय है। इस प्रकार onCreateViewHolder() में OnClickListener एस जैसी चीजें बनाने के लिए आम तौर पर बेहतर होता है ताकि वे केवल ViewHolder ऑब्जेक्ट पर एक बार हो जाएं। onBindViewHolder() पर प्रदत्त position तर्क लेने के बजाय, वर्तमान स्थिति प्राप्त करने के लिए श्रोता के अंदर getLayoutPosition() पर कॉल कर सकते हैं।

5

विधि पर बाइंडव्यूहोल्डर को हर बार बुलाया जाता है जब आप ऑब्जेक्ट के साथ अपना विचार बाध्य करते हैं जो अभी नहीं देखा गया है। और हर बार जब आप नए श्रोता जोड़ देंगे। आपको

@Override 
public Viewholder onCreateViewHolder(ViewGroup parent, int viewType) { 
    View v = LayoutInflater.from(parent.getContext()).inflate(itemLayout, parent, false); 
    final ViewHolder holder = new ViewHolder(v); 

    holder.itemView.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      Log.d(TAG, "position = " + holder.getAdapterPosition()); 
     } 
    }); 
    return new Viewholder(v); 
} 
संबंधित मुद्दे