본문 바로가기
어질어질 개발노트/Android

[Android] ListAdapter vs RecyclerViewAdapter: 무엇을 선택해야 할까?

by tia.mom 2025. 1. 10.
반응형

안드로이드 개발에서 데이터를 효율적으로 표시하기 위해 RecyclerView는 필수적인 컴포넌트입니다. RecyclerView는 데이터를 어댑터를 통해 화면에 바인딩하며, 대표적인 어댑터로 ListAdapterRecyclerViewAdapter가 있습니다. 이 글에서는 두 어댑터의 차이점, 각각의 장단점, 그리고 언제 어떤 어댑터를 사용해야 하는지에 대해 알아보겠습니다.


ListAdapter란?

ListAdapterRecyclerView.Adapter를 상속받아 구현된 어댑터로, DiffUtil을 내장하여 리스트 데이터의 변경 사항을 효율적으로 처리할 수 있도록 설계되었습니다. 데이터가 변경될 때 전체 데이터를 갱신하지 않고, 변경된 부분만 갱신하여 성능을 최적화합니다.

주요 특징

  1. DiffUtil 통합: 데이터 변경 사항을 자동으로 계산하여 UI 업데이트를 최소화.
  2. 간단한 구현: 별도의 DiffUtil 구현 없이도 효율적인 업데이트 가능.
  3. Immutable 데이터: 불변 데이터를 사용할 때 적합.

사용 예시

class SampleListAdapter : ListAdapter<MyItem, SampleListAdapter.MyViewHolder>(DiffCallback()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
        return MyViewHolder(view)
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val item = getItem(position)
        holder.bind(item)
    }

    class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(item: MyItem) {
            // 데이터 바인딩 처리
        }
    }

    class DiffCallback : DiffUtil.ItemCallback<MyItem>() {
        override fun areItemsTheSame(oldItem: MyItem, newItem: MyItem): Boolean {
            return oldItem.id == newItem.id
        }

        override fun areContentsTheSame(oldItem: MyItem, newItem: MyItem): Boolean {
            return oldItem == newItem
        }
    }
}
public class SampleListAdapter extends ListAdapter<MyItem, SampleListAdapter.MyViewHolder> {

    protected SampleListAdapter() {
        super(new DiffUtil.ItemCallback<MyItem>() {
            @Override
            public boolean areItemsTheSame(@NonNull MyItem oldItem, @NonNull MyItem newItem) {
                return oldItem.getId().equals(newItem.getId());
            }

            @Override
            public boolean areContentsTheSame(@NonNull MyItem oldItem, @NonNull MyItem newItem) {
                return oldItem.equals(newItem);
            }
        });
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        MyItem item = getItem(position);
        holder.bind(item);
    }

    static class MyViewHolder extends RecyclerView.ViewHolder {
        MyViewHolder(@NonNull View itemView) {
            super(itemView);
        }

        void bind(MyItem item) {
            // 데이터 바인딩 처리
        }
    }
}

RecyclerViewAdapter란?

RecyclerViewAdapterRecyclerView에서 가장 기본적으로 사용되는 어댑터입니다. 사용자 정의가 자유롭고 유연한 것이 장점이지만, 데이터 변경 시 DiffUtil을 수동으로 구현해야 합니다.

주요 특징

  1. 높은 유연성: 다양한 데이터 구조와 복잡한 로직 처리 가능.
  2. 직접적인 업데이트 제어: 데이터 변경 시 필요한 로직을 자유롭게 구현 가능.
  3. DiffUtil 필요: 데이터 변경 사항을 효율적으로 처리하려면 DiffUtil을 추가로 구현해야 함.

사용 예시

class SampleRecyclerViewAdapter : RecyclerView.Adapter<SampleRecyclerViewAdapter.MyViewHolder>() {

    private val items = mutableListOf<MyItem>()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
        return MyViewHolder(view)
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val item = items[position]
        holder.bind(item)
    }

    override fun getItemCount(): Int {
        return items.size
    }

    fun updateItems(newItems: List<MyItem>) {
        items.clear()
        items.addAll(newItems)
        notifyDataSetChanged()
    }

    class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(item: MyItem) {
            // 데이터 바인딩 처리
        }
    }
}
public class SampleRecyclerViewAdapter extends RecyclerView.Adapter<SampleRecyclerViewAdapter.MyViewHolder> {

    private final List<MyItem> items = new ArrayList<>();

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        MyItem item = items.get(position);
        holder.bind(item);
    }

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

    public void updateItems(List<MyItem> newItems) {
        items.clear();
        items.addAll(newItems);
        notifyDataSetChanged();
    }

    static class MyViewHolder extends RecyclerView.ViewHolder {
        MyViewHolder(@NonNull View itemView) {
            super(itemView);
        }

        void bind(MyItem item) {
            // 데이터 바인딩 처리
        }
    }
}

ListAdapter와 RecyclerViewAdapter의 차이점

특징 ListAdapter RecyclerViewAdapter
DiffUtil 내장 여부 있음 없음 (직접 구현 필요)
성능 최적화 자동 처리 수동 처리 필요
구현 복잡도 간단 높은 자유도 제공, 하지만 구현 복잡도 증가
사용 목적 Immutable 데이터와 간단한 리스트 처리에 적합 복잡한 로직이 필요하거나 높은 유연성이 요구되는 경우 적합

결론

어떤 어댑터를 사용할지는 앱의 요구사항에 따라 다릅니다. 데이터가 불변하며 변경 사항을 자동으로 처리하고 싶다면 ListAdapter가 적합합니다. 반면, 복잡한 데이터 구조나 로직이 필요하다면 RecyclerViewAdapter가 더 나은 선택일 수 있습니다.

개발 중 어떤 어댑터를 선택해야 할지 고민될 때는 위의 내용을 참고하여 적절한 어댑터를 선택하세요. 효율적인 어댑터 사용은 앱 성능 향상과 유지보수성 향상에 큰 기여를 할 것입니다.

반응형