리사이클러뷰의 구현요소나 구현결과물을 쉽게 변경 및 확장 가능 예) 리스트뷰는 수지방향으로만 아이템을 나열 할 수 있고 다른 방향으로 할려면 리스트뷰가 아닌 다른 뷰 사용 혹은 상당부분 재구현. 그에 비해 리사이클러뷰는 수직, 수평 방향으로 나열 가능 및 런타임시에 바꾸게 만들 수 있음.
나. 뷰 객체 재활용으로 성능 개선
리사이클러 뷰는 사용자가 아래로 스크롤 한다고 가정했을 때, 맨 위에 존재해서 이제 곧 사라질 뷰 객체를 삭제 하지않고 아랫쪽에서 새로 나타나날 파란색 뷰 위치로 객체를 이동시킨다. 즉 뷰 객체 자체를 재사용 하는 것인데, 중요한 점은 뷰 객체를 재사용 할 뿐이지 뷰 객체가 담고 있는 데이터(채팅방 이름)는 새로 갱신된다는 것이다. 어쨋거나 뷰 객체를 새로 생성하지는 않으므로 효율적인 것이다.
2. inner class _요약
inner class사용 유무에 따른 코드 쓰기에 앞서 자바와 코틀린은 중첩클래스 중 내부클래스(inner class)와 정적클래스(static class) 사용법이 정반대이다.
(첨부한 블로그에서는 nasted class라고 쓰셨는데 다른 블로그 참고해보니 nasted class가 중첩 클래스란 뜻이고 중첩안에 inner 와 static으로 구성되는 것 같다.)
요약
Inner classes를 사용할 경우 직렬화에 문제가 있다고 한다. -> 직렬화와 문제점에 대해서는 따로 포스팅예정입니다.
Inner classes 내부에 숨겨진 Outer class 정보를 보관하게 되고, 결국 참조를 해지하지 못하는 경우가 생기면 메모리 누수가 생길 수 있고, 코드를 분석하더라도 이를 찾기 쉽지 않다고 한다.
Inner classes를 허용하는 자바는 Outer를 참조하지 않아도 기본 inner classes이기 때문에(위에서 확인했다.) 불필요한 메모리 낭비와 성능 이슈를 야기한다고 한다.
결론
코틀린에서 outer의 멤버를 참고할 필요가 없다면 inner 예약어를 사용하지 않는게 좋다.
이럼에도 inner class 사용하는 경우를 포스팅하는 이유는 제가 코드 볼 때 헷갈렸기 때문입니당.(흑흑_)
- MainActivity.kt
Adapter와 LayoutManager 필수 작성
// recycler01 : 해당 kt파일의 xml의 리사이클러뷰(속성) id// ShareAdapter01 : Adapter.kt파일// datas : 리스트로 된 데이터 변수(다음 코드참고)
binding.recycler01.adapter=ShareAdapter01(datas)
layoutManager=GridLayoutManager(context,2) // 한행당 2개씩 보여주는 grid
- adapter는 데이터가 있는 리스트를 리사이클러뷰에 바인딩시켜주기위한 사전작업이 이루어지는 객체
- LayoutManager는 간단히 리사이클러뷰를 세로로 스크롤 할껀지 가로로 스크롤 할건지 격자로 볼건지 결정
전체 코드(apply적용 & 위와 같은 코드)
classMainActivity : AppCompatActivity() {
privateval binding: ActivityMainBinding by lazy{ActivityMainBinding.inflate(layoutInflater)}
overridefunonCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
val datas = Array(100) {
"chat $it"
}
// recycler01은 main_activity.xml에 있는 리사이클러뷰 id
binding.recycler01.apply{
adapter=ShareAdapter01(datas) // Adapter는 datas리스트를 리사이클러뷰에 바인딩시켜주기위한 객체
layoutManager=GridLayoutManager(context,2) // 한행당 2개씩 보여주는 grid
}
}
}
3. Adapter class 만들기 - inner class 사용 x
// 생성자로 리스트에 넣을 데이터 배열 받기classShareAdapter01(privatevar datas: Array<String>):RecyclerView.Adapter<Holder>(){
// Holder 객체 생성, 객체는 재사용 되기때문에 일정수만 호출된 후 호출xoverridefunonCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
// itemLayoutBinding : 아이템 목록 레이아웃뷰 객체화한 Binding classval binding = ItemLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return Holder(binding)
}
// 가장 먼저 실행되는 함수, 리사이클러뷰에 넣을 데이터 전체길이(datas길이) 리턴overridefungetItemCount(): Int {
return datas.size
}
// 생성된 뷰홀더에 데이터를 바인딩하는 함수, position인덱스 활용해 데이터만 바꿈(재사용), 새롭게 보여질 인텍스는 position으로 사용가능overridefunonBindViewHolder(holder: Holder, position: Int) {
holder.textField.text= datas[position]
}
}
// Holder 객체가 xml의 title 속성가지고 있음classHolder(val binding:ItemLayoutBinding): RecyclerView.ViewHolder(binding.root){
var textField= binding.title
}
맨 처음 화면에 보이는 전체 리스트 목록이 딱 10개라면, 위아래 버퍼를 생각해서 13~15개 정도의 뷰 객체가 생성된다. 정확하게 말하자면 뷰 객체를 담고 있는 ViewHolder가 생성되는 것이다. 그래서 onCreateViewHolder함수는 딱 13~15번 정도만 호출되고 더 이상 호출되지 않는다.
onBindViewHolder는 스크롤을 해서 데이터 바인딩이 새롭게 필요할 때 마다 호출된다. 스크롤을 무한정 돌린다면, onBindViewHolder도 무한정 호출된다. 무한정 호출된다 하더라도 우리는 딱 13~15개의 뷰 객체만 사용하는 꼴이다.
4.Adapter 만들기 - inner class 사용 O
classShareAdapter01(privatevar datas: Array<String>):RecyclerView.Adapter<Holder>(){
// Holder class를 inner class로, onBindViewHolder 기능도 여기서 처리innerclassHolder(val binding:ItemLayoutBinding): RecyclerView.ViewHolder(binding.root){
// onBindViewHolder 기능 bind 함수에서 처리funbind(positon: Int){
binding.title.text=data[position] // title은 아이템 목록 xml 속성id
}
}
overridefunonCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
// itemLayoutBinding : 아이템 목록 레이아웃뷰 객체화한 Binding classval binding = ItemLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return Holder(binding)
}
overridefungetItemCount(): Int {
return datas.size
}
overridefunonBindViewHolder(holder: Holder, position: Int) {
holder.bind(position)
}
}
Holder클래스를 inner로 만들고 나서 onBindViewHolder역할도 그 안에서 처리해줬다. 이 코드를 중첩리사이클러뷰 시도할 때 봤는데 헷갈렸어서 정리해보았다.
다음에는 클릭리스너 달기 - > 중첩리사이클러뷰 클릭리스너 달기에 대해 포스팅하겠습니당~🥰🥰