Strong 감자의 공부

RecyclerView01 -Kotlin 본문

활동 기록/졸업작품 with Kotlin

RecyclerView01 -Kotlin

ugyeong 2023. 3. 31. 21:52

중첩리사이클러뷰에 이벤트넣다가 안됐다. (너무 헷갈렸어요) 그래도 얻은건 있었따... inner class, Scope function을 계속 접하다보니 헷갈렸던 개념 좀 외워진듯...?😀😀하하... 

이번기회에 리사이클러뷰에 대해 정리 해보는 시간 갖고 다시 도전해보는걸로~

-오늘 포스팅 내용-

1. 리사이클러뷰란? _요약

2. inner class  _요약

3. inner class 사용 x 방식 

4. inner class 사용 o 방식

 

 

스으으타토🥰🥰


1. 리사이클러뷰란?  _요약

오늘 포스팅의 주된 내용은 리사이클러뷰 작성 방식과 클릭리스너에 뒀다. (초심자인 저에게 엄청 헷갈렸던 부분이라서욤)그리고 이미 많은 곳에서 리사이클러뷰vs리스트와 장점 및 작성 대해 자세히 정말 잘 설명해주기때문에 url과 요약만 납기려합니당. https://wooooooak.github.io/android/2019/03/28/recycler_view/

 

  • 리사이클러뷰 장점 

 

       가. 유연함 

            리사이클러뷰의 구현요소나 구현결과물을 쉽게 변경 및 확장 가능 예) 리스트뷰는 수지방향으로만 아이템을 나열              할 수 있고 다른 방향으로 할려면 리스트뷰가 아닌 다른 뷰 사용 혹은 상당부분 재구현. 그에 비해 리사이클러뷰는              수직, 수평 방향으로 나열 가능 및 런타임시에 바꾸게 만들 수 있음.

 

       나. 뷰 객체 재활용으로 성능 개선

리사이클러 뷰는 사용자가 아래로 스크롤 한다고 가정했을 때, 맨 위에 존재해서 이제 곧 사라질 뷰 객체를 삭제 하지않고 아랫쪽에서 새로 나타나날 파란색 뷰 위치로 객체를 이동시킨다. 즉 뷰 객체 자체를 재사용 하는 것인데, 중요한 점은 뷰 객체를 재사용 할 뿐이지 뷰 객체가 담고 있는 데이터(채팅방 이름)는 새로 갱신된다는 것이다.
어쨋거나 뷰 객체를 새로 생성하지는 않으므로 효율적인 것이다.

 


2. inner class  _요약

inner class사용 유무에 따른 코드 쓰기에 앞서 자바와 코틀린은 중첩클래스 중 내부클래스(inner class)와 정적클래스(static class) 사용법이 정반대이다. 

이 이유에 대해서 이 블로그에서 자세히 잘 설명해 주셨다. https://velog.io/@huijiny/Kotlin-Inner-Nested-classes

(첨부한 블로그에서는 nasted class라고 쓰셨는데 다른 블로그 참고해보니 nasted class가 중첩 클래스란 뜻이고 중첩안에 inner 와 static으로 구성되는 것 같다.)

 

요약

  1. Inner classes를 사용할 경우 직렬화에 문제가 있다고 한다. -> 직렬화와 문제점에 대해서는 따로 포스팅예정입니다.
  2. Inner classes 내부에 숨겨진 Outer class 정보를 보관하게 되고, 결국 참조를 해지하지 못하는 경우가 생기면 메모리 누수가 생길 수 있고, 코드를 분석하더라도 이를 찾기 쉽지 않다고 한다.
  3. 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적용 & 위와 같은 코드)

class MainActivity : AppCompatActivity() {
    private val binding: ActivityMainBinding by lazy{ActivityMainBinding.inflate(layoutInflater)}
    override fun onCreate(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  

// 생성자로 리스트에 넣을 데이터 배열 받기
class ShareAdapter01(private var datas: Array<String>):RecyclerView.Adapter<Holder>(){

 // Holder 객체 생성, 객체는 재사용 되기때문에 일정수만 호출된 후 호출x
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
   // itemLayoutBinding : 아이템 목록 레이아웃뷰 객체화한 Binding class
        val binding = ItemLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return Holder(binding)
    }
    
 // 가장 먼저 실행되는 함수, 리사이클러뷰에 넣을 데이터 전체길이(datas길이) 리턴
    override fun getItemCount(): Int {
        return datas.size
    }
    
 // 생성된 뷰홀더에 데이터를 바인딩하는 함수, position인덱스 활용해 데이터만 바꿈(재사용), 새롭게 보여질 인텍스는 position으로 사용가능
    override fun onBindViewHolder(holder: Holder, position: Int) {
        holder.textField.text= datas[position]
    }
  }
 // Holder 객체가 xml의 title 속성가지고 있음
class Holder(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

class ShareAdapter01(private var datas: Array<String>):RecyclerView.Adapter<Holder>(){

// Holder class를 inner class로,  onBindViewHolder 기능도 여기서 처리
	inner class Holder(val binding:ItemLayoutBinding): RecyclerView.ViewHolder(binding.root){
	// onBindViewHolder 기능 bind 함수에서 처리
        fun bind(positon: Int){
        	binding.title.text=data[position] // title은 아이템 목록 xml 속성id
        }
  }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
    
   // itemLayoutBinding : 아이템 목록 레이아웃뷰 객체화한 Binding class
        val binding = ItemLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return Holder(binding)
    }
    

    override fun getItemCount(): Int {
        return datas.size
    }
    

    override fun onBindViewHolder(holder: Holder, position: Int) {
        holder.bind(position)
    }
  }

Holder클래스를 inner로 만들고 나서 onBindViewHolder역할도 그 안에서 처리해줬다. 이 코드를 중첩리사이클러뷰 시도할 때 봤는데 헷갈렸어서 정리해보았다.

 

다음에는 클릭리스너 달기 - > 중첩리사이클러뷰 클릭리스너 달기에 대해 포스팅하겠습니당~🥰🥰

 

 

참고)

https://wooooooak.github.io/android/2019/03/28/recycler_view/

https://velog.io/@huijiny/Kotlin-Inner-Nested-classes