RecyclerView.Adapter의 onBindViewHolder 내에 OnClickListener를 추가하는 것이 왜 나쁜 습관으로 간주됩니까?
RecyclerView.Adapter
클래스에 대해 다음 코드가 있으며 제대로 작동합니다.
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를 구현하는 것은 나쁜 습관이라고 생각합니다 . 이것이 왜 나쁜 습관이며 더 나은 대안은 무엇입니까?
ViewHolder 내에서 클릭 로직을 처리하는 것이 더 좋은 이유는 더 명시적인 클릭 리스너를 허용하기 때문입니다. Commonsware 책에 표현 된대로 :
Clickable widgets, like a RatingBar, in a ListView row had long been in conflict with click events on rows themselves. Getting rows that can be clicked, with row contents that can also be clicked, gets a bit tricky at times. With RecyclerView, you are in more explicit control over how this sort of thing gets handled… because you are the one setting up all of the on-click handling logic.
By using the ViewHolder model you can gain a lot of benefits for click handling in a RecyclerView than previously in the ListView. I wrote about this in a blog post comparing the differences - https://androidessence.com/recyclerview-vs-listview
As for why it is better in the ViewHolder instead of in onBindViewHolder()
, that is because onBindViewHolder()
is called for each and every item and setting the click listener is an unnecessary option to repeat when you can call it once in your ViewHolder constructor. Then, if your click responds depends on the position of the item clicked, you can simply call getAdapterPosition()
from within the ViewHolder. Here is another answer I've given that demonstrates how you can use the OnClickListener
from within your ViewHolder class.
The onCreateViewHolder()
method will be called the first several times a ViewHolder
is needed of each viewType
. The onBindViewHolder()
method will be called every time a new item scrolls into view, or has its data change. You want to avoid any expensive operations in onBindViewHolder()
because it can slow down your scrolling. This is less of a concern in onCreateViewHolder()
. Thus it's generally better to create things like OnClickListener
s in onCreateViewHolder()
so that they only happen once per ViewHolder
object. You can call getLayoutPosition()
inside the listener in order to get the current position, rather than taking the position
argument provided to onBindViewHolder()
.
The method onBindViewHolder
is called every time when you bind your view with object which just has not been seen. And every time you will add a new listener.
Instead what you should do is, attaching click listener on onCreateViewHolder
example :
@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 holder;
}
Pavel provided great code example except one line in the end. You should return created holder. Not the new Viewholder(v).
@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 holder;
}
Per https://developer.android.com/topic/performance/vitals/render, onBindViewHolder
should do its work in "much less than one millisecond" to prevent slow rendering.
RecyclerView: Bind taking too long
Bind (that is, onBindViewHolder(VH, int)) should be very simple, and take much less than one millisecond for all but the most complex items. It simply should take POJO items from your adapter's internal item data, and call setters on views in the ViewHolder. If RV OnBindView is taking a long time, verify that you're doing minimal work in your bind code.
'program story' 카테고리의 다른 글
console.log 대신 angular의 $ log를 사용하는 이유는 무엇입니까? (0) | 2020.11.21 |
---|---|
Python의 asyncio 모듈을 사용하여 동시 작업을 올바르게 생성하고 실행하는 방법은 무엇입니까? (0) | 2020.11.21 |
C ++ 17의 새로운 범위 기반 for 루프가 Ranges TS에 어떻게 도움이 되나요? (0) | 2020.11.21 |
Visual Studio : "다른 네임 스페이스로 클래스 이동"리팩토링이 있습니까? (0) | 2020.11.21 |
C #이 내 제네릭 유형을 유추하지 않는 이유는 무엇입니까? (0) | 2020.11.21 |