본문 바로가기

Android

(Part.1) 리사이클러뷰에서 여러 타입의 데이터 사용하기

목표

리사이클러뷰의 아이템을 접을 수 있는 기능 구현하기.

할 일(Task)의 수가 많아질 경우 원하는 할 일을 찾으려면 스크롤을 많이 해야하는 경우가 생긴다.

  • Header를 사용해서 Task를 분류하도록 한다.
  • Header를 클릭하면 하위에 속한 Task 아이템을 접을 수 있도록 한다.

RecyclerView Adapter

어댑터의 기본 기능은 사용자에게 RecyclerView에 내용을 채워넣어 보여주는 역할이다.

여기서 내용(Data)는 음식에 비유할 수 있고, 뷰홀더는 음식을 담는 그릇이라고 생각해보자.

어댑터는 음식에 어울리는 그릇을 찾고, 음식을 담아서 고객에게 내보내는 직원의 역할을 한다.

어댑터 직원이 다루는 음식은 List 타입으로 다루어지며,
onCreateViewHolder()와 onBindViewHolder()라는 메소드는 각각 그릇을 생성하고, 그릇에 음식을 담는 행위를 수행한다.

문제점

가장 눈에 띄는 문제점은 우리는 Header와 Task라는 서로 다른 두 종류의 음식을 다루어야 하는데,

Adapter는 기본적으로 하나의 List를 통해서 음식들을 관리한다.

하나의 리스트로 여러가지 음식들(자료형)을 관리하기 위해서 AdapterType이라는 새로운 인터페이스를 만들어서 해결하도록 하자.

이제 Header와 Task라는 두 가지 음식 모두 List 안에 넣어둘 수 있다.

그릇 생성하기

// Adapter.java
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    ItemType = ItemType.getItem(viewType);

    switch (type) {
        case HEADER:
            View view = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.header_item, parent, false);
            return new HeaderViewHolder(view, this);
        case TASK:
            View view = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.task_item, parent, false);
            return new TaskViewHolder(view, this);
    }

    return null;
}

이번에 전달받은 음식의 타입을 확인하고 타입에 알맞은 그릇을 꺼내온다.(ViewHolder를 생성한다.)

그릇에 음식 담기

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    final AdapterType item = data.get(position);

    switch (item.getItemType()) {
        case HEADER:
            // 데이터를 알맞은 타입으로 형변환하는 과정이 필요하다.
            final Header header = (Header) item;
            // 전달받은 holder를 데이터 타입과 맞는 ViewHolder로 형변환하는 과정이 필요하다.
            final HeaderViewHolder headerViewHolder = (HeaderViewHolder) holder;

            // 그릇에 음식 담기
            headerViewHolder.header = header.getTitle();

        case TASK:
            final Task task = (Task) item;
            final TaskViewHolder taskViewHolder = (TaskViewHolder) holder;

            taskViewHolder.title = task.getTitle();
            taskViewHolder.desc = task.getDesc();
    }
}

문제점

하나의 어댑터 내에서 Header와 Task 두 가지 자료형을 모두 사용하여 리사이클러 뷰에 데이터를 내보낼 수 있도록 구현하였다.

 

하지만 제 3의 다른 타입을 추가하기 위해서는 AdapterType 인터페이스를 구현해야하고,
어댑터 내부의 onCreateViewHolder(), onBindViewHolder()에서 switch 문을 이용한 하드코딩을 할 수 밖에 없는 한계가 생겼다.

 

이 구조는 갈수록 어댑터의 코드가 엄청나게 복잡해질 수 밖에 없다.

서로 다른 데이터를 제어하는 코드를 계속해서 추가해나가거나, 새로운 타입을 위한 전용 어댑터를 새로 만드는 수 밖에 없다.