티스토리 뷰
RecyclerView의 item에 Custom View를 넣고 싶을 때
이슈
- RecyclerView가 10개의 아이템을 가지고 있다고 하였을 때, 0번째 item에서의 Custom View에서 특정 작업을 했던 것이 7번째 item의 Custom View에도 영향을 줍니다.
- 즉, 별개의 Custom View로 동작해야하는데 서로가 서로에게 영향을 줬습니다.
- 0번째, 7번째가 서로 영향을 주는 것은 특정 상황에서만 나온 것이고 서로 영향을 주는 객체는 매번 달라졌습니다.
수정 전 코드
지금껏 해왔던대로 RecyclerView의 item 레이아웃(item_layout.xml)에 직접 만든 Custom View를 넣어서 사용함.
(저 같은 경우에는 GraphView를 만들었습니다.)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/item_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.mycompany.graph.GraphView
android:id="@+id/graph_item"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
- RecyclerView Adapter의 ViewHolder 클래스는 다음과 같이 정의하였습니다.
class ViewHolder extends RecyclerView.ViewHolder {
private final RelativeLayout itemLayout;
private final GraphView graphView;
ViewHolder(View view) {
super(view);
itemLayout = view.findViewById(R.id.item_layout);
graphView = view.findViewById(R.id.graph_item);
}
}
- onBindViewHolder에서 Custom View의 설정을 추가해줬습니다.
@Override
public void onBindViewHolder(@NonNull GraphAdapter.ViewHolder holder, int position) {
GraphView graphView = holder.graphView;
graphView.configure();
}
문제
- 제가 생각하기로는 RecyclerView의 ViewHolder가 재사용하는 과정에서 ViewHolder에서 이미 만들어놨던 Custom View를 활용하면서 서로에게 영향을 준 것 같습니다.
- 즉, 같은 ViewHolder를 활용하므로 Custom View의 객체도 같은 객체를 활용하기 때문입니다.
- 실제로 onBindViewHolder에서 position별로 각 holder의 Custom View의 객체 id값을 확인한 결과는 다음과 같습니다.
position | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|---|
id | 06f3 | d291 | 2f54 | 83d1 | d194 | f8f0 | 983f | 06f3 | d291 | 2f54 |
- 위 표를 보시면 0번째, 1번째, 2번째 id값이 각각 7, 8, 9번째 id값에 대응됨을 볼 수 있습니다.
해결
- RecyclerView.Adapter에서 Custom View의 리스트를 갖고 있다가 onBindViewHolder가 호출될 때마다 각 position에 맞는 holder에 Custom View를 addView하는 식으로 처리하였습니다.
item_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/item_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</RelativeLayout>
CustomAdapter.class
class GraphAdapter extends RecyclerView.Adapter<GraphAdapter.ViewHolder> {
private List<GraphView> graphViews = new ArrayList<>();
private Context context;
GraphAdapter(Context context) {
this.context = context;
}
public void setGraphViews(int num) {
this.graphViews.clear();
for (int i = 0; i < num; i++) {
GraphView graphView = new GraphView(context);
this.graphViews.add(graphView);
}
notifyDataSetChanged();
}
@NonNull
@Override
public GraphAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_graph, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull GraphAdapter.ViewHolder holder, int position) {
if (graphViews.get(position).getParent() != null) {
((ViewGroup) graphViews.get(position).getParent()).removeView(graphViews.get(position));
}
holder.itemLayout.addView(graphViews.get(position));
}
@Override
public int getItemCount() {
return graphViews.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
private final RelativeLayout itemLayout;
ViewHolder(View view) {
super(view);
itemLayout = view.findViewById(R.id.item_layout);
}
}
}
- 위 경우에는 Custom View의 개수를 setGraphViews(int num)라는 함수를 통해서 받고 Custom View를 하나씩 생성한 다음에 graphViews라는 List타입의 변수에 넣어둡니다.
- onBindViewHolder에서 graphViews안에 들어 있는 Custom View를 하나씩 꺼내서 itemLayout(RelativeLayout)에 addView해줍니다.
- onBindViewHolder에서 holder가 재사용되는 것을 반복하면서 Custom View의 parentView가 달라질 수 있는데 따라서 parent가 이미 배정되어 있는 경우라면 해당 Custom View를 parent에서 해제하기 위해서 아래 코드를 추가하였습니다.
if (graphViews.get(position).getParent() != null) {
((ViewGroup) graphViews.get(position).getParent()).removeView(graphViews.get(position));
}
회고
- 저의 경우에는 위와 같이 해결을 하였지만 성능을 위해서 최적의 방법은 아닐 수 있습니다.
- 좋은 의견이 있으면 남겨주시면 감사하겠습니다.
반응형
'Programming > 안드로이드(Android)' 카테고리의 다른 글
Android 클린 아키텍처 (0) | 2021.09.16 |
---|---|
[안드로이드] Data binding 사용 시 Caused by: android.content.res.Resources$NotFoundException: String resource ID #0x0 Error (0) | 2021.06.03 |
[안드로이드] ProgressBar에 애니메이션 적용 (0) | 2021.05.13 |
[안드로이드] 구글 플레이 콘솔 기기 0대에서 사용 가능 (uses-feature) (0) | 2021.05.11 |
[안드로이드] 스레드와 핸들러 (feat. 깡샘) (0) | 2021.05.11 |
댓글