Android Studio - RecyclerView

Minjae Lee·2024년 2월 17일

Android Studio

목록 보기
3/12

1. RecyclerView 개념

RecyclerView is a flexible view for providing a limited window into a large data set.
리사이클러뷰는 많은 데이터셋을 제한된 화면에서 표시할 수 있도록 도와준다.
(Android Developers - RecyclerView)

위의 설명은 안드로이드 스튜디오 공식 문서에서 제공한 설명인데, 다소 추상적이어서 이해하기 힘들 수 있다. 이해하기 쉽게 조금 바꿔보면, 아래와 같이 쓸 수 있다.

리사이클러뷰는 사용자가 원하는 데이터들을 화면에 띄워주는 역할을 한다.

예를 들어, 존재하는 모든 사용자들의 아이디와 닉네임, 전화번호를 띄우려고 한다면 (아이디, 닉네임, 전화번호)를 묶어 저장하고, 해당 데이터들을 지정된 양식에 맞추어 띄우면 된다.

  • (아이디, 닉네임, 전화번호)를 묶어서 아이템(Item)이라고 부른다.

RecyclerView에서 Recycle은 재활용이라는 뜻을 가지고 있다. 아이템을 화면에 나타내기 위해 사용한 틀을 재활용하기 때문에 붙여졌다. 따라서 유사한 양식의 요소를 앱에 띄우려면 디자인을 일일히 하는 것이 아니라 RecyclerView를 사용해야 한다.

  • 보여지는 틀을 뷰(View)라고 한다.

2. RecyclerView 구성 요소

2-1. 어댑터(Adapter)

앞서 설명했듯이, RecyclerView는 저장된 데이터 묶음을 화면에 띄워주는 역할을 한다. 저장된 아이템들은 눈에 보이지 않기 때문에, 아이템을 앱에서 보여주기 위해서는 특별한 요소인 어댑터(Adapter)를 사용해야 한다. Adapter는 말 그대로 데이터와 View를 연결해주는 역할을 한다.

2-2. 레이아웃매니저(LayoutManager)

Adapter를 사용하고 나서, 아이템을 어떻게 보여줄지 정해야 한다. 아이템을 세로로 보여줄 수도 있고, 가로로 보여줄 수도 있으며, 이외에도 다양한 방식이 존재한다. 이러한 종류를 결정해주는것이 레이아웃매니저(LayoutManager)의 역할이다. 자주 사용하는 LayoutManaer는 크게 3종류가 있다.

  • LinearLayoutManager(Vertical)
  • LinearLayoutManager(Horizontal)
  • GridLayoutManager

2-3. 뷰홀더(ViewHolder)

뷰홀더(ViewHolder)는 화면에 표시되는 뷰를 저장하는 역할을 한다. ViewHolder는 Adapter에 의해 관리 및 생성된다. RecyclerView는 View를 재활용하기에, 미리 생성된 ViewHolder가 있으면 새로 생성하지 않는다. 이 때, 데이터가 뷰홀더의 아이템에 바인딩(Binding)된다고 한다.

2-4. 모식도

3. RecyclerView 사용

3-0. Workflow

RecyclerView를 사용하기 위해서 아래의 과정을 거쳐야 한다.
1. xml파일에 RecyclerView 추가
2. item view xml파일 생성
3. Adapter 구현
4. RecyclerView와 Adapter 연결

3-1. xml파일에 RecyclerView 추가

Palette-Common 탭에서 RecyclerView를 찾아 드래그 앤 드롭한다. 드래그 앤 드롭을 하고 나면, 흰 배경에 item 0, item 1, ... 이 생긴다. 해당 item 0, item 1, ... 은 3-4 과정에서 Adapter 연결을 통해 바꿀 수 있다.

  • activity_main.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:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

3-2. item view xml파일 생성

layout 폴더에 item view를 위한 xml 파일을 생성한다. item 내용을 띄울 TextView를 적당히 배치하고, 디자인한다. 이 때, 가장 바깥쪽의 ConstraintLayout의 height는 wrap_content, width는 match_parent로 설정해야 한다.
필자의 경우 사용자의 이름, 전화번호를 띄우기 위해 TextView를 2개 사용하였으며, 그림자 효과를 주었다. 아래는 xml코드 및 화면 사진이다.

  • person_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content"
    android:layout_margin="10dp"
    android:background="#FFFFFF"
    android:elevation="20dp"
    android:paddingTop="10dp"
    android:paddingBottom="10dp">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.11"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageView"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.26" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageView"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.76" />
</androidx.constraintlayout.widget.ConstraintLayout>

3-3. Adapter 구현

RecyclerView는 개발자가 직접 Adapter를 구현하여 사용해야 한다. 이 때 Adapter는 RecyclerView.Adapter를 상속받아야한다.

public class UserAdapter extends RecyclerView.Adapter<UserAdapter.ViewHolder> {

}

위와 같이 Adapter Class의 큰 틀을 완성하였으면, Adapter내에 ViewHolder Class도 만들어주어야 한다. ViewHolder Class는 RecyclerView.ViewHolder를 상속받아야 한다. ViewHolder Class의 역할은 크게 2가지이다.

  • 위에서 만든 person_item.xml에서 필요한 요소를 찾는 역할
  • 찾은 요소들을 편집하는 역할

저장한 데이터셋에 맞추어 보여지는 itemView를 편집해야 하기에, 위의 두 함수는 꼭 필요하다.

public static class ViewHolder extends RecyclerView.ViewHolder {
    public TextView username, userphone;
    public ImageView imageView, star;
    public View parentView;

    public ViewHolder(View view) {
        super(view);
        username = view.findViewById(R.id.textView);
        userphone = view.findViewById(R.id.textView2);
    }

    public void setItem(Item item) {
        username.setText(item.name);
        userphone.setText(item.phone);
    }

    public TextView getUserId() { return username; }
    public TextView getUserBirth() { return userphone; }
}

아래의 함수들을 처음 만든 Adapter Class 안에 선언한 후, override해줘야 한다.

  • onCreateViewHolder(ViewGroup parent, int viewType) : itemView를 위한 ViewHolder 객체 생성 함수. 쉽게 말해 person_item.xml 파일을 RecyclerView에서 사용할 것임을 설정한다.
  • onBindViewHolder(ViewHolder holder, int position) : 데이터셋에서 position에 해당하는 데이터를 ViewHolder의 itemView에 표시하는 함수.
  • getItemCount() : 전체 item 개수를 return하는 함수.
    위 함수들의 코드 구성은 아래와 같다.
public ArrayList<Item> items = new ArrayList<>();

@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    View view = LayoutInflater.from(viewGroup.getContext())
            .inflate(R.layout.person_item, viewGroup, false);

    return new ViewHolder(view);
}

@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
    Item item = items.get(position);
    viewHolder.setItem(item);
}


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

다음으로 새로운 item을 추가하는 함수인 addItem(Item item)을 추가해준다.

public void addItem(Item item) {
    items.add(item);
}

마지막으로 데이터를 저장할 Item Class를 만든다. 이 또한 Adapter Class 안에 만들어야 나중에 사용이 쉬워진다. 필자의 경우 사용자의 이름과 전화번호를 쌍으로 묶어 저장해야 하므로 Item Class를 아래와 같이 구성하였다. 추가 데이터가 필요할 경우 유동적으로 코드를 수정하면 된다.

public static class Item {
    String name, phone;

    public Item(Item item){
        this(item.name, item.phone);
    }

    public Item(String name, String phone) {
        this.name = name;
        this.phone = phone;
    }
}

전체적인 코드는 아래와 같다.

  • UserAdapter.java
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.ViewHolder> {

    public ArrayList<Item> items = new ArrayList<>();

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView username, userphone;

        public ViewHolder(View view) {
            super(view);
            username = view.findViewById(R.id.textView);
            userphone = view.findViewById(R.id.textView2);
        }

        public void setItem(Item item) {
            username.setText(item.name);
            userphone.setText(item.phone);
        }
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        View view = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.person_item, viewGroup, false);

        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int position) {
        Item item = items.get(position);
        viewHolder.setItem(item);
    }


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

    public void addItem(Item item) {
        items.add(item);
    }

    public static class Item {
        String name, phone;

        public Item(Item item){
            this(item.name, item.phone);
        }

        public Item(String name, String phone) {
            this.name = name;
            this.phone = phone;
        }
    }
}

3-4. RecyclerView와 Adapter 연결

위의 과정을 통해 Adapter를 모두 구현하였으면, RecyclerView를 사용할 Activity로 이동해야 한다. 이동 후, RecyclerView와 Adapter를 연결해주면 RecyclerView에 아이템이 보여지게 된다. 연결하기에 앞서, 먼저 Adapter 객체를 할당해줘야 한다.
UserAdapter adapter = new UserAdapter();

onCreate 함수 안에서 RecyclerView를 findViewById 함수를 이용해 RecyclerView를 찾는다. 이후 LayoutManager를 이용해 Adapter의 item이 보여질 방향을 설정한 후, setAdapter 함수를 이용해 RecyclerView와 Adapter를 연결해준다.

LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);

마지막으로 Adapter에 우리가 만든 addItem 함수를 이용해 item을 추가한다. item을 추가하고 난 뒤에는 adapter의 item이 바뀌었음을 notifyDataSetChanged 함수를 이용해 명시해줘야 한다.

adapter.addItem(new UserAdapter.Item("김민수", "010-1000-1000"));
adapter.addItem(new UserAdapter.Item("김하늘", "010-2000-2000"));
adapter.addItem(new UserAdapter.Item("홍길동", "010-3000-3000"));

adapter.notifyDataSetChanged();

전체 코드는 아래와 같다.

  • MainActivity.java
public class MainActivity extends AppCompatActivity {

    RecyclerView recyclerView;
    UserAdapter adapter = new UserAdapter();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = findViewById(R.id.recyclerView);

        LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.VERTICAL, false);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(adapter);

        adapter.addItem(new UserAdapter.Item("김민수", "010-1000-1000"));
        adapter.addItem(new UserAdapter.Item("김하늘", "010-2000-2000"));
        adapter.addItem(new UserAdapter.Item("홍길동", "010-3000-3000"));

        adapter.notifyDataSetChanged();
    }
}

3-5. 결과

모든 코드를 작성한 후, 실행시키면 아래와 같은 화면이 뜨는 것을 확인할 수 있다.

0개의 댓글