반응형

(210518 수정)

 

리사이클러뷰(RecyclerView)는 안드로이드 개발을 할 때에 굉장히 많이 사용된다.

왜냐하면 가장 많이 사용되는 UI의 모양들 중 하나이기 때문이다.

이전에 게시했던 채팅앱만 봐도 리사이클러뷰로 구현했다는 것을 알 수 있을 것이다.

 

기본적으로 사용되는 ListView와 비슷하지만 ListView의 기능에 추가적으로

레이아웃 설정도 자유롭고(유연성 증가), 효율성도 더 좋다(성능 발전).

 

RecyclerView가 어떤 것인지 간단하게 알아보고

이에 대한 구현 방법을 알아보겠다.

 

우선 리사이클러뷰(RecyclerView)란 무엇인가?

 

첫 번째,

언뜻 보면 비슷해보이지만

RecyclerView가 ListView와 다른 점은 재활용, 즉 재사용을 할 수 있다는 뷰라는 점에서

차이점을 보인다. 재사용을 하면 어떻게 다를까?

 

이전에 올린 채팅앱을 예시로 설명해보자.

예를 들어

100개의 채팅 메시지가 있고 화면에는 10개의 채팅 메시지만 보인다.

(채팅앱에서의 뷰 객체라고 하면 보통 말풍선을 나타내는 아이템 뷰이다.)

 

여기서 ListView는,

사용자가 스크롤을 위아래로 움직이면 맨 위에 있는 뷰 객체가 삭제되고

맨 아래에 새롭게 뷰 객체가 생성되는 것을 수 십번 수 백번 그 이상의 갱신을 반복하게 된다.

이렇게 되면 결과적으로

성능을 저하시키게 되는 요인이 된다.

 

하지만 RecyclerView는?

맨 위의 뷰 객체를 삭제하지 않고 맨 아래로 이동시켜

재사용(Recycle)을 한다.

하지만 뷰 객체 자체를 재사용하는 것일뿐,

뷰 객체가 가지고 있는 데이터는 새롭게 만들어진다.

 

화면에 10개의 채팅 메시지만 보이면 되기 때문에

몇 백 몇 천개의 채팅 메시지 데이터가 있든 말든

결국 뷰 객체는 10개만 있으면 된다.

 

두 번째,

레이아웃을 보다 유연하게 설정할 수 있다.

수직으로만 가능했던 ListView 한계점을 극복하고

RecyclerView에서는 수평도 가능하다.

 

이 부분은 LayoutManager라는 객체를 사용해서 설정하는데,

아래 코드들에서 다뤄볼 것이다.

 

-----------------------------------------------------------------------------------------

 

이제부터 RecyclerView를 간단하게 구현하면서 알아보자.

 

이번에는 카카오톡 같은 채팅앱의 채팅창 화면이 아닌

채팅할 친구목록을 구현해 볼 것이다.

 

먼저, 메인 친구목록(RecyclerView) 화면을 보여주는 activity_main.xml부터 작성해보자.

 

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
 
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
 
</LinearLayout>
cs

간단하게 RecyclerView만 구현해볼 것이기 때문에 (아직은 껍데기 상태의) RecyclerView만 넣는다.

 

그리고 친구목록을 보여주는 각 친구의 간단프로필을 list_item.xml로 만들건데,

이것은 어댑터의 인플레이션을 통해 뷰 객체가 될 것이다. 

 

list_item.xml

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:background="@drawable/item_line">
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
 
        <ImageView
            android:id="@+id/iv"
            android:layout_width="77dp"
            android:layout_height="match_parent" />
 
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_weight="1">
 
            <TextView
                android:id="@+id/tvName"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="이름"
                android:textSize="40sp" />
 
            <TextView
                android:id="@+id/tvStmsg"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="상태 메시지"
                android:textSize="25sp" />
            
        </LinearLayout>
    </LinearLayout>
</LinearLayout>
cs

 

아이템에 테두리를 만들어주고 코너를 둥글게 한다.

 

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
 
    <stroke android:width="1dp" />
 
    <corners
        android:radius="15dp" />
</shape>
cs

</shape>

친구의 간단프로필을 보여줄 아이템

그 다음으로는 친구목록의 데이터 정보를 담고 있는 Friends.java 라는 모델을 만든다.

Friends.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.example.recyclerviewtest;
 
public class Friends {
    String name; // 이름
    String stateMsg; // 상태메시지
    int resId; // 이미지 아이디
 
    public Friends(String name, String stateMsg, int resId) {
        this.name = name;
        this.stateMsg = stateMsg;
        this.resId = resId;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getStateMsg() {
        return stateMsg;
    }
 
    public void setStateMsg(String stateMsg) {
        this.stateMsg = stateMsg;
    }
 
    public int getResId() {
        return resId;
    }
 
    public void setImageView(int resId) {
        this.resId = resId;
    }
}
 
cs
 
 
 

 

처음에 만들었던 activity_main.xml에서의 RecyclerView는 껍데기에 불과하다.

이 RecyclerView를 실제로 화면에 보여지게 하려면 

어댑터(Adapter)를 통해서 데이터와 연결을 해야한다.

 

FriendsAdapter.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class FriendsAdapter extends RecyclerView.Adapter<FriendsAdapter.ViewHolder> {
 
    ArrayList<Friends> items = new ArrayList<Friends>(); // 아이템 리스트, 여러 아이템을 어댑터가 관리해야하기 때문에 어레이 리스트형 변수 선언
 
    @NonNull
    @Override // 리사이클러뷰에서 보여지는 여러 개의 아이템은 내부에서 캐시되기 때문에 아이템 갯수만큼 객체가 만들어지는 것은 아님
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());// 인플레이션을 하려면 Context 객체가 필요한데 뷰 그룹 객체의 getContext()를 이용하면 Context 참조 가능함함
       View itemView = inflater.inflate(R.layout.list_item, parent, false); // 뷰 그룹 객체는 각 아이템 뷰를 위한 뷰 그룹 객체이므로 xml을 인플레이션하여 이 뷰그룹 객체에 설정
 
        return new ViewHolder(itemView); // 뷰홀더 객체를 생성하면서 뷰 객체를 전달하고 그 뷰홀더 객체를 반환
    }
 
    @Override // 뷰홀더가 재사용될 때 호출되므로 뷰 객체는 기존 것을 그대로 사용하고 데이터만 바꿔줌
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Friends item = items.get(position); // 재활용 가능한 뷰홀더 객체를 파라미터로 전달하기 때문에 그 뷰홀더에 맞는 현재 아이템에 맞는 데이터만 설정(현재 몇 번째 것이 보여야 되는 시점인가)
        holder.setItem(item); // 핸들러에 아이템을 설정
    }
 
    @Override
    public int getItemCount() { // 어댑터가 관리하는 아이템의 갯수를 알아야 할 때 사용
        return items.size();
    }
 
    static class ViewHolder extends RecyclerView.ViewHolder {
        TextView tvName;
        TextView tvStmsg;
       ImageView iv;
 
        public ViewHolder(@NonNull View itemView) { // 뷰홀더 생성자로 전달되는 뷰 객체를 참조함(아이템들은 뷰로 만들어지고, 뷰는 뷰홀더에 담아둠)
            super(itemView); // 이 뷰 객체를 부모 클래스의 변수에 담아둠
 
           // 뷰 객체에 들어 있는 텍스트뷰를 참조함
            tvName = itemView.findViewById(R.id.tvName);
            tvStmsg = itemView.findViewById(R.id.tvStmsg);
           iv= itemView.findViewById(R.id.iv);
        }
 
        public void setItem(Friends item) {
            tvName.setText(item.getName());
            tvStmsg.setText(item.getStateMsg());
           iv.setImageResource(item.getResId());
        }
 
    }
 
    // 이 어댑터가 아이템을 위한 Friends 객체를 어레이 리스트 안에 넣어 관리하기 때문에
    // 이 어댑터를 사용하는 소스코드에서 어댑터에 Friends 객체를 넣거나 가져갈 수 있도록 아래의 메소드들을 추가
 
    public void addItem(Friends item) {
        items.add(item); // 어레이 리스트에다 아이템 추가
    }
 
    public void setItems(ArrayList<Friends> items) {
        this.items = items;
    }
 
    public void getItem(int position) {
        items.get(position);
    }
 
    public void setItem(int position, Friends item) {
        items.set(position, item);
    }
}
 
cs}

 

어댑터를 통해서 아이템 뷰와 데이터를 연결했다면

MainActivity 클래스에서

어댑터의 addItem() 메서드를 이용해 Friends 객체를 추가한다.

 

MainActivity.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        RecyclerView recyclerView = findViewById(R.id.recyclerView);
 
        LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); // 리니어 레이아웃 매니저를 생성해서 레이아웃 방향을 설정함(vertical)
        recyclerView.setLayoutManager(layoutManager); // 리사이클러뷰에 레이아웃 매니저 객체 설정-> 리니어 레이아웃으로 설정됨
        FriendsAdapter adapter = new FriendsAdapter(); // 리사이클러뷰와 어댑터 상호작용
 
        // 어댑터에 아이템을 추가함(Friends 객체의 이름, 상태 메시지, 프로필 이미지)
        adapter.addItem(new Friends("하빌리즘""안녕하세요", R.drawable.flower));
        adapter.addItem(new Friends("비둘기""gugugu", R.drawable.gugu));
        adapter.addItem(new Friends("하빌리즘""안녕하세요", R.drawable.flower));
        adapter.addItem(new Friends("비둘기""gugugu", R.drawable.gugu));
        adapter.addItem(new Friends("하빌리즘""안녕하세요", R.drawable.flower));
        adapter.addItem(new Friends("비둘기""gugugu", R.drawable.gugu));
        adapter.addItem(new Friends("하빌리즘""안녕하세요", R.drawable.flower));
        adapter.addItem(new Friends("비둘기""gugugu", R.drawable.gugu));
        adapter.addItem(new Friends("하빌리즘""안녕하세요", R.drawable.flower));
        adapter.addItem(new Friends("비둘기""gugugu", R.drawable.gugu));
        adapter.addItem(new Friends("하빌리즘""안녕하세요", R.drawable.flower));
        adapter.addItem(new Friends("비둘기""gugugu", R.drawable.gugu));
        adapter.addItem(new Friends("하빌리즘""안녕하세요", R.drawable.flower));
        adapter.addItem(new Friends("비둘기""gugugu", R.drawable.gugu));
        adapter.addItem(new Friends("하빌리즘""안녕하세요", R.drawable.flower));
        adapter.addItem(new Friends("비둘기""gugugu", R.drawable.gugu));
 
        recyclerView.setAdapter(adapter); // 리사이클러뷰에 어댑터를 설정함
 
    }
}
cs}

최종 실행 화면

 

간단하게 RecyclerView에 대해서 알아보았는데

개인적으로 많은 공부가 되었고,

보시는 분들에게 조금이나마 도움이 되셨으면 좋겠다.

 

피드백은 언제나 환영입니다.

반응형

+ Recent posts