Android

RecyclerView 기초

Dean83 2022. 6. 9. 12:20

일단, RecyclerView를 보면서 느낀점은 왜 이렇게 복잡하게 해놨지? 였다. 

WPF에서는 금방, 그리고 간단하게 구성될 List 와 데이터 연동이 안드로이드에선 몇단계의 세팅을 걸쳐서 이루어진다. 

왜 이렇게 불편하게 해놓은건지 모르겠다. 몇번을 해야 기억이 쏙 들러올련지 원....

일단 기본적으로 간단하게 string 데이터를 표시하는 예제를 구현했다. 

 

1. 필요 구성 요소들
    - RecyclerView 를 레이아웃에 추가 해야함
    - RecyclerView.Adapter를 상속받는 adapter 클래스를 추가해야함
       - 해당 클래스 내부에 RecyclerView.ViewHolder 를 상속받는 클래스를 가져야 함
    - Activity 든 fragment든 RecyclerView를 사용하는 곳에서 여러 세팅을 해줘야 함.
    - RecyclerView의 각 아이템을 보여줄 layout을 생성해야함 (List 의 한 라인을 담당할 레이아웃)

그럼 하나씩 살펴보면

2. RecyclerView를 layout에 추가

     - 간단히 layout에 RecyclerView를 선택 - 드래그 드랍으로 배치한다. 

3. Adapt 클래스 및 하위 Holder 클래스 생성
    - Adapt 클래스는 RecyclerView.Adapt 클래스를 상속 받아야 한다. 
       - 상속 받을때, ViewHolder 클래스를 자료형으로 넣어줘야 한다.
       - 생성 인자값으로 View와 연결할 데이터를 받아야 한다. (예 : Array<String>)
       - onCreateViewHolder, onBindViewHolder, getItemCount 함수를 오버라이드 해야한다. 
    - Adapt 클래스 내부에 ViewHolder를 상속받는 내부 클래스 생성 해야한다
       - 해당 클래스는 View를 생성자에서 받아야 한다.
       - 아래에서 기술할, RecyclerView 의 각 Row 항목의 layout 의 view  항목들에 실제 데이터를 입력할 수 있도록 코딩해야한다.

public class adapter(val dataSet : Array<String>) : Adapter<adapter.holder>() {

    public class holder(itemView: View) : RecyclerView.ViewHolder(itemView)
    {

        val textView : TextView

        init {
            textView = itemView.findViewById(R.id.textView)
            textView.setOnClickListener {

            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): holder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.recycleviewitem,parent,false)
        return holder(view)
    }

    override fun onBindViewHolder(holder: holder, position: Int) {
        holder.textView.text = dataSet[position]
    }

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

 4. RecyclerView의 각 Row 에 해당하는 layout 생성
      - 안드로이드 스튜디오 -> project -> 마우스 우클릭 -> new -> Android Resource File -> layout 선택 후 새로 생성

      - 필요에 맞게 view 를 이용해서 화면구성. ( id값 필수) 
      - 최상위 태그에 android:layout_height는 꼭 wrap_content로 설정한다. 

 

5. Activity 혹은 fragment에서 RecyclerView 세팅

     - RecyclerView의 layoutmanager 설정
        - LayoutManager는  LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager 3개가 있다.
     - Adapter 연결
        - 연결할 데이터 전달

//샘플 데이터 생성
var tempItem = ArrayList<String>()
for (i : Int in 0..100)
{
    tempItem.add(i.toString())
}

 var adapt : adapter = adapter(tempItem.toArray(arrayOfNulls<String>(tempItem.size)) )
var review : RecyclerView = view.findViewById(R.id.recycleView)
//가로형으로 설정시 코드
//review.layoutManager = LinearLayoutManager(container?.context, RecyclerView.HORIZONTAL, false)

//세로형. 샘플코드는 fragment에서 추가한거라 context 를 가져오는 코드가 다르다. 
review.layoutManager = LinearLayoutManager(container?.context)
review.adapter = adapt

 

그럼, 리사이클 뷰의 데이터가 변경되었을때 UI에 반영하는 방법이 필요할 것이다. 

 

6. 데이터 갱신 to RecycleView

    - adapter의 notifyDataSetChanged() 를 이용하여, 데이터의 추가/삭제/수정 등의 항목 변경이 있음을 알린다. 

 

7. 데이터 갱신시 이벤트 받기
    - adapter의 registerAdapterDataObserver 를 통해 데이터가 변경되었을때 이벤트 핸들러를 등록할 수 있다. 

    - java에서는 간단히 추가하는법을 알고 있는데 코틀린에선 어떻게 하는지 모르겠다. 그래서 좀 복잡한 방식으로 풀었다. 
    - 일단, RecyclerView.AdapterDataObserver 클래스를 상속받는 클래스를 생성한다
    - Activity 혹은 fragment 클래스에서 위에 적은 클래스형 변수를 생성한다
    - adapter.registerAdapterDataObserver 의 인자값으로 해당 변수를 추가한다.

//클래스 생성 및 onChanged 함수 오버라이드
class AdaptUpdate : RecyclerView.AdapterDataObserver()
{
    override fun onChanged() {
        super.onChanged()

        Log.d("test","onchanged")
    }
}

...

//위에서 작성한 클래스형 변수 생성
private lateinit var adaptupdate : AdaptUpdate

adaptupdate = AdaptUpdate()
...

//adapter에 위에서 생성한 변수를 인자값으로 전달
 adapt.registerAdapterDataObserver(adaptupdate)

 이렇게 할 경우, 데이터가 변경되면 위에 작성한 클래스의 onChanged가 호출된다