본문 바로가기
공부/Android Studio

RecyclerView 정리

by Piva 2021. 2. 8.

  요즘 공부를 심각하게 안해서... 졸업작품을 하는 겸 + 그러는 김에 안드로이드 스튜디오를 공부할 겸 구현한 내용을 기반으로 기록이나 남겨볼까 한다.

 

  RecyclerView를 그 시작으로 삼는 이유는 구현이 복잡해서였다. 구현 순서를 잘 모르는 채 참고서만 잡고 무작정 돌진하니 이해도 안가고 이걸 왜 이렇게 하는건지 알 수 있을리가 없었다. 공식 설명서만 읽어도 이해가 될 것을... 여기에선 공식 문서 설명(+참고 문헌)을 읽고 이해한 내용을 정리한다.

 

 


1. RecyclerView

  'RecyclerView'는 이름만 봐선 그 용도를 짐작하기 어려우나 일반적으로 목록(리스트)를 만드는데 이용된다. 목록을 만들 때 그 속에 무엇이 얼마나 들어갈지도 미리 알 수 없으면서 그 항목들을 일일이 만들어줄 수 있을리 없다. 그러나 상황에 따라 목록 속의 항목들을 '동적'으로 줄 수 있다면 편할 것이다. RecyclerView는 바로 그 동적 목록 생성의 역할을 수행한다. 그리고 명칭 그대로 뷰를 '재활용'하여 활용하기 때문에, 앱의 성능 개선에도 기여할 수 있다. (어떻게 재활용을 하는지는 후에 언급한다.)

 

  목록을 구현하는 데에는 ListView 또한 하나의 선택지가 될 수 있으나, '동적이고 유연하다'라는 장점 덕분에 일반적으로는 RecyclerView를 권장하고 있는 것 같다. (공식 문서의 ListView 항목에서도 이러한 점을 언급하고 있다.)

 

1-1. 실제 사용

  'RecyclerView'는 외부 라이브러리이기 때문에, 안드로이드 스튜디오에서 사용하기 위해서는 따로 다운로드를 해야 한다. Pallette에 다운로드 버튼이 있으므로, 이를 통해 간단하게 다운로드 받을 수 있다.

 

  다운로드가 끝난 후 RecyclerView를 추가해보면, xml코드 상으로 다음과 같이 추가된다.

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    
</LinearLayout>

  이렇게 되면 RecyclerView의 추가는 간단하게 끝난다. 다음으론 RecyclerView 속에 넣을 항목과, 항목을 추가하기 위한 작업을 수행한다.

 

2. 구현 순서

  공식 문서에서 언급하는 구현 단계를 간단하게 정리하면 다음과 같다.

 

  1. 목록의 모양(형태)을 결정한다.

  2. 목록 속 항목의 모양과 기능을 설계한다. → 'ViewHolder' 확장

  3. 데이터를 ViewHolder와 연결하는 'Adapter'를 정의한다.

  모르는 용어가 나오기 시작한다. 실제로 어거지로 졸작을 구현하려 했을 때도 여기서부터 뭔지 모르는 것들이 출연해서 당황했다. 각 단계를 좀더 해석해본다.

 

 

1. 목록의 모양(형태)을 결정한다.

  RecyclerView 속에 들어갈 항목들이 어떤 모양(레이아웃)으로 들어갈 지를 결정해주는 단계이다. 이 때 사용하는 것이 'LayoutManager'이다. RecyclerView에서 사용할 수 있는 레이아웃 관리자는 총 3가지다. 나는 LinearLayoutManager 이외엔 사용해본적이 없어서, 나머지 2개의 차이는 공식 문서를 통해 파악했다. (기회가 된다면 써보고 싶다.)

 

LinearLayoutManager 항목을 1차원으로 정렬한다.
말그대로 LinearLayout 속에 항목들을 정렬한다고 생각하면 ok.
정렬 방향은 vertical, horizontal 모두 설정 가능하다.
GridLayoutManager 항목을 격자(2차원) 모양으로 정렬한다.
StaggeredGridLayoutManager GridLayoutManager와 마찬가지로 격자 모양으로 정렬한다.
다만 GridLayoutManager가 격자 속 항목들을 동일 높이/너비로 고정시키는 반면, StaggeredGridLayoutManager에서는 그런 제한이 없다는 것 같다.

 

  LayoutManager는 다음 예시코드와 같은 식으로 설정하면 된다. 

 

RecyclerView recyclerView;

public View onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

		...
        
        recyclerView = rootView.findViewById(R.id.recyclerView);

        LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
        recyclerView.setLayoutManager(layoutManager);

		...

    }

 

 

2. 목록 속 항목의 모양과 기능을 설계한다.

  레이아웃을 결정했으면, 리스트의 각 항목의 레이아웃 또한 구현해주어야 한다. 이 때 CardView를 곧잘 쓰는 것 같다. (CardView에 대해선 나중에 또 알아볼 것...)

 

  항목 레이아웃 구현까지 완료되면 'ViewHolder'를 확장해야 한다. ViewHoler는 명칭 그대로 리스트 속 항목 뷰를 '담아두는' 역할을 수행한다. 후에 언급할 'Adapter'가 ViewHolder 객체를 만들고 데이터를 설정하기 때문에, Adapter를 구현할 때 RecyclerView.ViewHolder 클래스를 상속하여 ViewHolder를 정의하게 되는 것 같다. Adapter와 ViewHolder로 각 뷰(리스트 내 항목)에 데이터를 연결하는 과정을 '바인딩'이라 부른다.

 

  ViewHolder를 정의할 때는 리스트의 각 항목에 들어갈 뷰들을 넣어주면 된다. 예시 코드는 다음과 같다.

 

//Adapter.java
public class Adapter extends RecyclerView.ViewHolder<Adapter.ViewHolder>{

    public static class ViewHolder extends RecyclerView.ViewHolder {

        ImageView imageView;
        TextView textView;

        public ViewHolder (View view) {
            super(view);

            imageView = view.findViewById(R.id.imageView);
            textView = view.findViewById(R.id.textView);
        }
    }
}

 

  위의 코드는 리스트에 들어갈 항목들이 이미지와 텍스트뷰 하나씩으로 구성되어있다고 가정한 코드이다. Adapter를 구현할 JAVA파일 안에 ViewHolder 클래스를 확장하여 작성된다. 다만 저 코드를 그대로 사용하면 에러가 나올 텐데, 이는 RecyclerView.Adapter 클래스에서 구현해야 하는 메서드를 다 구현하지 않았기 때문이다. 이 메서드들에 대해선, 다음 단계에서 Adapter를 언급할 때 같이 이야기한다.

 

 

 

3. 데이터를 ViewHolder와 연결하는 'Adapter'를 정의한다.

  공식 문서의 순서를 따라가느라 ViewHolder를 먼저 언급하게 되었지만 드디어 Adapter까지 왔다.

  

  Adapter는 ViewHolder 객체를 만들고 바인딩을 수행하는 역할을 한다. 즉, 데이터를 뷰에 연결하는 과정을 Adapter가 담당하기 때문에 재활용하여 띄울 원본 데이터를 Adapter에 연결해야 한다. 그렇기 때문에 리스트의 레이아웃을 Adapter 내에 설정해주어야 하는 것 같다.

 

  앞서 Adapter의 정의에는 꼭 구현해야 하는 메서드가 있다고 언급하였는데, 해당 메서드들은 총 3가지로 아래와 같다.

 

onCreateViewHolder() ViewHolder 객체를 새로이 생성할 때 호출된다. 이 때, 리스트 속 항목을 위해 정의한 xml 레이아웃을 통해 뷰 객체를 만든다. 다만, 뷰의 내용은 채워지지 않는다.
onBindViewHolder() ViewHolder에 데이터를 바인딩할 때 호출된다. 즉, 데이터를 가져와서 뷰 레이아웃의 내용물을 여기서 채운다.
getItemCount() 전체 아이템 개수를 가져올 때 호출하는 메서드.

 

  ViewHolder가 재사용된다는 말은, 리스트 내 뷰를 띄우는 것과 관련있다. 리스트 내 항목이 많으면 조그만 스마트폰 화면에 그것들이 다 보일리가 없다. 그렇기에 전체 항목의 개수만큼 뷰 객체를 만드는 것이 아니라, 사용자가 화면을 스크롤함에 따라 보이지 않게되는 객체들을 재활용해서 다시 띄운다. 이런 방식을 통하면 효율적으로 리스트를 띄우는 것이 가능하다.

 

 

 

3. 마무리

  ViewHolder의 예시 코드는 간단하게 작성하였지만(공식 문서가 그랬어서...), 실제로 구현에 사용할 때는 리스트에 띄울 데이터의 클래스를 따로 정의해서 사용하게 되는 것 같다. 그에 따라 부가적인 기능도 구현해야 하다보니, 이래저래 어려움을 겪었던 것 같다.

 

  그래도 이렇게 한 번 정리해보았으니 다음 번에 다시 구현해볼때는 까먹지 않으리라 믿으며...

 

 

더보기

 

'공부 > Android Studio' 카테고리의 다른 글

ImageView (feat. 오늘의 뻘짓)  (0) 2021.03.17
CardView 정리  (1) 2021.02.08