기록장
[안드로이드] RecyclerView(리사이클러뷰) 본문
바로 이전 포스팅에서는 ListView에 대해 다뤄보았다. 이번엔 겉으로 보기에 리스트뷰와 기능이 똑같은 RecyclerView에 대해 알아보겠다.
RecyclerView는 리스트뷰와 마찬가지로 데이터 목록들을 리스트형식으로 보여주는 역할을 한다.
기능이 똑같고 둘 다 어댑터를 이용해서 구현되는데(리스트뷰는 꼭 어댑터 아니여도 되긴하지만,,) 왜 비슷한게 두개나 있을까 라고 생각될 수 있다.
이유는 리사이클러뷰에는 메모리를 효율적으로 사용하도록 캐시(Cache) 메커니즘이 구현되어 있다.
이름에서 알수 있듯이 재활용 View이다. 리사이클러뷰에 보이는 여러 개의 아이템은 내부에서 캐시되기 때문에 아이템 개수만큼 객체가 만들어지지 않고 ViewHolder에 담아 두었다가 스크롤하여 보이지 않게 되는 뷰 객체를 새로 보여질 아이템 항목에 재사용된다.
그래서 결론적으로 리스트뷰보다 리사이클러뷰를 더 권장한다고 한다.
리사이클러뷰에 주요 메소드를 알아보도록 하겠다. 대부분 어댑터에서 구현된다.
- onCreateViewHolder(): ViewHolder 객체가 만들어질 때 호출, 보통 이 때 뷰를 만들어서 ViewHolder에 넣어준다.
- onBindViewHolder(): 재사용할 때 호출, 스크롤하면서 보이는 아이템 항목이 바뀔 때마다 호출
- getItemCount(): 현재 아이템 항목 개수 반환
- RecyclerView.ViewHolder를 상속 시 ViewHolder 클래스: 이건 클래스인데 생성자에 어댑터 액티비티에 대한 View 객체가 전달된다.
잘 이해가 안된다면 코드에 주석을 잘 읽어보길 권장한다.
리사이클러뷰를 사용하기 위해서는 라이브러리를 추가해줘야 한다.
implementation 'androidx.recyclerview:recyclerview:1.1.0'
코드
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"
tools:context=".MainActivity"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/edittext1"
android:hint="이름"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/edittext2"
android:hint="내용"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/button1"
android:text="버튼"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recyclerview"/>
</LinearLayout>
이름과 내용을 입력하고 버튼을 누르면 리사이클러뷰 리스트에 추가되도록 만들 예정이다.
MainActivity.java
public class MainActivity extends AppCompatActivity {
ArrayList<list> list = new ArrayList<>();
adapter connection_adapter;
RecyclerView recyclerView;
Button b1;
EditText et1, et2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.recyclerview);
connection_adapter = new adapter(this, list);
//리사이클러뷰에 레이아웃 매니저 설정, 리니어레이아웃매니저로 VERTICAL, HORIZONTAL 방향 설정 가능
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(connection_adapter); //리사이클러뷰에 어댑터 설정
b1 = findViewById(R.id.button1);
et1 = findViewById(R.id.edittext1);
et2 = findViewById(R.id.edittext2);
b1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
list item_list = new list(); //아이템 항목 클래스 객체 생성
item_list.setName(et1.getText().toString()); //아이템 항목 설정
item_list.setMemo(et2.getText().toString()); //마찬가지
list.add(item_list); //ArrayList로 선언된 list에 데이터 add
connection_adapter.notifyDataSetChanged(); //리사이클러뷰 갱신
}
});
}
}
adapter.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="wrap_content"
tools:context=".adapter"
android:orientation="vertical"
android:id="@+id/linearlayout1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/ic_launcher_foreground"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/textview1"
android:textSize="30dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:textSize="20dp"
android:text="부서: 미정"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="10dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textview2"
android:textSize="20dp"/>
</LinearLayout>
</LinearLayout>
아이템 항목에 나올 화면을 구성하는 어댑터.xml
adapter.java
//RecyclerView.Adapter 클래스 상속(오버라이드 되는 메소드는 onCreateViewHolder(), onBindViewHolder(), getItemCount())
public class adapter extends RecyclerView.Adapter<adapter.ViewHolder> {
Activity context;
ArrayList<list> list = new ArrayList<>();
//메인 액티비티에서 데이터를 ArrayList 형식으로 ViewHolder에 담겨있는 View에 데이터 적용할 수 있도록 가져옴
adapter(Activity context, ArrayList<list> list){
this.context = context;
this.list = list;
}
//상속하여 정의한 ViewHolder
class ViewHolder extends RecyclerView.ViewHolder{
LinearLayout linearLayout;
TextView tv1, tv2;
//생성자에 View 객체가 전달(itemView)
public ViewHolder(@NonNull View itemView) {
super(itemView);
linearLayout = itemView.findViewById(R.id.linearlayout1);
tv1 = itemView.findViewById(R.id.textview1);
tv2 = itemView.findViewById(R.id.textview2);
}
}
//ViewHolder 객체가 만들어질 때 호출
@NonNull
@Override
public adapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//최초 객체가 만들어질 때 각 아이템 항목들을 보여주기 위한 View 객체 생성
//생성된 View를 ViewHolder에 담아둬야 하므로 return new ViewHolder(View)
LayoutInflater inflater = LayoutInflater.from(parent.getContext()); //getContext()로 Context 객체 참조
View itemView = inflater.inflate(R.layout.activity_adapter, parent, false);
return new ViewHolder(itemView);
}
//viewType 파라미터는 각 아이템을 위한 View를 여러 가지로 나누어 보여주고 싶을 때 사용
//ex) 어떤 때는 이미지를 보여주고 어떤 때는 이미지, 텍스트를 같이 보여주고 싶을 때 View 타입을 정하고 각 View 타입에 따라 다른 xml을 인플레이션하여 보여줌
//ViewHolder가 재사용될 때 호출
@Override
public void onBindViewHolder(@NonNull adapter.ViewHolder holder, final int position) {
//ViewHolder 클래스의 생성자 내에서 어댑터.xml에 대한 위젯 설정을 다 해놓았고
//Holder의 View에 list에 있는 데이터를 설정해준다.
holder.tv1.setText(list.get(position).getName());
holder.tv2.setText(list.get(position).getMemo());
//어댑터.xml의 리니어레이아웃이 눌리면 반응
holder.linearLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, list.get(position).getName() +"\n" +list.get(position).getMemo(),Toast.LENGTH_SHORT).show();
}
});
}
//아이템 개수 반환
@Override
public int getItemCount() {
return list.size();
}
}
아이템 항목에 들어갈 아이템들 저장을 위한 클래스
list.java
public class list {
String name;
String memo;
public String getName() {
return name;
}
public String getMemo() {
return memo;
}
public void setName(String name) {
this.name = name;
}
public void setMemo(String memo) {
this.memo = memo;
}
}
결과
아이템 항목 누를 시
+ 추가
Grid 형태로 보여주기
GridLayoutManager layoutManager = new GridLayoutManager(this, 2); //두칸이면 2, 세칸이면 3
recyclerView.setLayoutManager(layoutManager);
레이아웃 설정만 바꿔주면 된다.
결과
아이템 항목 클릭되도록 하기
public ViewHolder(@NonNull View itemView) {
super(itemView);
linearLayout = itemView.findViewById(R.id.linearlayout1);
tv1 = itemView.findViewById(R.id.textview1);
tv2 = itemView.findViewById(R.id.textview2);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context,"아이템 눌림",Toast.LENGTH_SHORT).show();
}
});
}
ViewHolder 안에서 메소드 생성해서 사용
부족한 점, 피드백 환영합니다.
감사합니다.
참고
정재곤, 『Do it! 안드로이드 앱 프로그래밍 - 개정 6판』, 이지스퍼블리싱(주)
'안드로이드' 카테고리의 다른 글
[안드로이드] Broadcast Receiver(브로드캐스트 리시버) / 브로드캐스트 리시버 종류 (0) | 2021.01.14 |
---|---|
[안드로이드] Service(서비스) 이해하기 (0) | 2021.01.13 |
[안드로이드] ListView(리스트뷰) (0) | 2021.01.12 |
[안드로이드] Volley(볼리) 통신 / RequestQueue (0) | 2021.01.09 |
[안드로이드] 웹, HTTP 통신, 공공데이터 API, JSON 파일 데이터 가져오기 / HttpURLConnection, JSON Parsing(제이슨 파싱), 공공데이터포털 (0) | 2021.01.08 |